Commit 43d84147 authored by Andy Ross's avatar Andy Ross Committed by Carles Cufi
Browse files

drivers/pcie: Fix BAR address size limitation



The PCI API was originally limited to 32 bit addresses.  Even though
it had code to skip over the high word in 64 bit BAR entries, it
refused to use it and returned a 32 bit value.  Some devices in the
wild have default mappings from the firmware for devices above 4G.

Also remove the "iobar" API.  It's dead code, we don't call it and we
don't test it.  IO space BAR entries are a legacy feature from way,
way back in PCI history (I genuinely have never heard of a real device
that uses them!).  And there's no difference in format between one of
these and a 32 bit "memory" BAR anyway, someone who actually had this
requirement could just use the existing API without worry.

Signed-off-by: default avatarAndy Ross <andrew.j.ross@intel.com>
parent 83464f11
Loading
Loading
Loading
Loading
+13 −29
Original line number Diff line number Diff line
@@ -46,37 +46,26 @@ void pcie_set_cmd(pcie_bdf_t bdf, uint32_t bits, bool on)
	pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmdstat);
}

static uint32_t pcie_get_bar(pcie_bdf_t bdf, unsigned int index, bool io)
uintptr_t pcie_get_mbar(pcie_bdf_t bdf, unsigned int index)
{
	int bar;
	uint32_t data;
	uint32_t reg, bar;
	uintptr_t addr = PCIE_CONF_BAR_NONE;

	for (bar = PCIE_CONF_BAR0; bar <= PCIE_CONF_BAR5; ++bar) {
		data = pcie_conf_read(bdf, bar);
		if (data == PCIE_CONF_BAR_NONE) {
			continue;
	reg = PCIE_CONF_BAR0;
	for (bar = 0; bar < index && reg <= PCIE_CONF_BAR5; bar++) {
		if (PCIE_CONF_BAR_64(pcie_conf_read(bdf, reg++))) {
			reg++;
		}

		if ((PCIE_CONF_BAR_IO(data) && io) ||
		    (PCIE_CONF_BAR_MEM(data) && !io)) {
			if (index == 0) {
				return PCIE_CONF_BAR_ADDR(data);
	}

			--index;
		}

		if (PCIE_CONF_BAR_64(data)) {
			++bar;
		}
	if (bar == index) {
		addr = pcie_conf_read(bdf, reg++);
		if (IS_ENABLED(CONFIG_64BIT) && PCIE_CONF_BAR_64(addr)) {
			addr |= ((uint64_t)pcie_conf_read(bdf, reg)) << 32;
		}

	return PCIE_CONF_BAR_NONE;
	}

uint32_t pcie_get_mbar(pcie_bdf_t bdf, unsigned int index)
{
	return pcie_get_bar(bdf, index, false);
	return PCIE_CONF_BAR_ADDR(addr);
}

unsigned int pcie_wired_irq(pcie_bdf_t bdf)
@@ -86,11 +75,6 @@ unsigned int pcie_wired_irq(pcie_bdf_t bdf)
	return PCIE_CONF_INTR_IRQ(data);
}

uint32_t pcie_get_iobar(pcie_bdf_t bdf, unsigned int index)
{
	return pcie_get_bar(bdf, index, true);
}

void pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq)
{
#if CONFIG_PCIE_MSI
+3 −13
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ extern bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id);
 * @brief Get the nth MMIO address assigned to an endpoint.
 * @param bdf the PCI(e) endpoint
 * @param index (0-based) index
 * @return the (32-bit) address, or PCI_CONF_BAR_NONE if nonexistent.
 * @return the address, or PCI_CONF_BAR_NONE if nonexistent.
 *
 * A PCI(e) endpoint has 0 or more memory-mapped regions. This function
 * allows the caller to enumerate them by calling with index=0..n. If
@@ -82,17 +82,7 @@ extern bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id);
 * are order-preserving with respect to the endpoint BARs: e.g., index 0
 * will return the lowest-numbered memory BAR on the endpoint.
 */
extern uint32_t pcie_get_mbar(pcie_bdf_t bdf, unsigned int index);

/**
 * @brief Get the nth I/O address assigned to an endpoint.
 * @param bdf the PCI(e) endpoint
 * @param index (0-based) index
 * @return the (32-bit) address, or PCI_CONF_BAR_NONE if nonexistent.
 *
 * Analogous to pcie_get_mbar(), except returns I/O region data.
 */
extern uint32_t pcie_get_iobar(pcie_bdf_t bdf, unsigned int index);
extern uintptr_t pcie_get_mbar(pcie_bdf_t bdf, unsigned int index);

/**
 * @brief Set or reset bits in the endpoint command/status register.
@@ -180,7 +170,7 @@ extern void pcie_irq_enable(pcie_bdf_t bdf, unsigned int irq);
#define PCIE_CONF_BAR_IO(w)		(((w) & 0x00000001U) == 0x00000001U)
#define PCIE_CONF_BAR_MEM(w)		(((w) & 0x00000001U) != 0x00000001U)
#define PCIE_CONF_BAR_64(w)		(((w) & 0x00000006U) == 0x00000004U)
#define PCIE_CONF_BAR_ADDR(w)		((w) & 0xFFFFFFF0U)
#define PCIE_CONF_BAR_ADDR(w)		((w) & ~0xfUL)
#define PCIE_CONF_BAR_NONE		0U

/*