drivers/pcie: Change pcie_get_mbar() to return size and flags

currently pcie_get_mbar only returns the physical address.
This changes the function to return the size of the mbar and
the flags (IO Bar vs MEM BAR).

Signed-off-by: Maximilian Bachmann <m.bachmann@acontis.com>
This commit is contained in:
Maximilian Bachmann 2020-11-05 00:15:25 +01:00 committed by Johan Hedberg
commit 3c8e98cb39
7 changed files with 76 additions and 36 deletions

View file

@ -79,15 +79,15 @@ int arch_printk_char_out(int c)
void z_x86_early_serial_init(void) void z_x86_early_serial_init(void)
{ {
#if defined(DEVICE_MMIO_IS_IN_RAM) && !defined(UART_NS16550_ACCESS_IOPORT) #if defined(DEVICE_MMIO_IS_IN_RAM) && !defined(UART_NS16550_ACCESS_IOPORT)
uintptr_t phys;
#ifdef X86_SOC_EARLY_SERIAL_PCIDEV #ifdef X86_SOC_EARLY_SERIAL_PCIDEV
phys = pcie_get_mbar(X86_SOC_EARLY_SERIAL_PCIDEV, 0); struct pcie_mbar mbar;
pcie_get_mbar(X86_SOC_EARLY_SERIAL_PCIDEV, 0, &mbar);
pcie_set_cmd(X86_SOC_EARLY_SERIAL_PCIDEV, PCIE_CONF_CMDSTAT_MEM, true); pcie_set_cmd(X86_SOC_EARLY_SERIAL_PCIDEV, PCIE_CONF_CMDSTAT_MEM, true);
device_map(&mmio, mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE);
#else #else
phys = X86_SOC_EARLY_SERIAL_MMIO8_ADDR; device_map(&mmio, X86_SOC_EARLY_SERIAL_MMIO8_ADDR, 0x1000, K_MEM_CACHE_NONE);
#endif #endif
device_map(&mmio, phys, 0x1000, K_MEM_CACHE_NONE);
#endif /* DEVICE_MMIO_IS_IN_RAM */ #endif /* DEVICE_MMIO_IS_IN_RAM */
OUT(REG_IER, IER_DISABLE); /* Disable interrupts */ OUT(REG_IER, IER_DISABLE); /* Disable interrupts */

View file

@ -584,10 +584,10 @@ may be used directly:
void some_init_code(...) void some_init_code(...)
{ {
... ...
uintptr_t phys_addr = pcie_get_mbar(...); struct pcie_mbar mbar;
size_t size = ... bool bar_found = pcie_get_mbar(bdf, index, &mbar);
device_map(DEVICE_MMIO_RAM_PTR(dev), phys_addr, size, K_MEM_CACHE_NONE); device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE);
... ...
} }

View file

@ -217,20 +217,18 @@ int e1000_probe(const struct device *device)
const pcie_bdf_t bdf = PCIE_BDF(0, 3, 0); const pcie_bdf_t bdf = PCIE_BDF(0, 3, 0);
struct e1000_dev *dev = device->data; struct e1000_dev *dev = device->data;
uint32_t ral, rah; uint32_t ral, rah;
uintptr_t phys_addr; struct pcie_mbar mbar;
size_t size;
if (!pcie_probe(bdf, PCIE_ID(PCI_VENDOR_ID_INTEL, if (!pcie_probe(bdf, PCIE_ID(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_I82540EM))) { PCI_DEVICE_ID_I82540EM))) {
return -ENODEV; return -ENODEV;
} }
phys_addr = pcie_get_mbar(bdf, 0); pcie_get_mbar(bdf, 0, &mbar);
pcie_set_cmd(bdf, PCIE_CONF_CMDSTAT_MEM | pcie_set_cmd(bdf, PCIE_CONF_CMDSTAT_MEM |
PCIE_CONF_CMDSTAT_MASTER, true); PCIE_CONF_CMDSTAT_MASTER, true);
size = KB(128); /* TODO: get from PCIe */
device_map(&dev->address, phys_addr, size, device_map(&dev->address, mbar.phys_addr, mbar.size,
K_MEM_CACHE_NONE); K_MEM_CACHE_NONE);
/* Setup TX descriptor */ /* Setup TX descriptor */

View file

@ -611,17 +611,17 @@ static int i2c_dw_initialize(const struct device *dev)
#ifdef I2C_DW_PCIE_ENABLED #ifdef I2C_DW_PCIE_ENABLED
if (rom->pcie) { if (rom->pcie) {
uintptr_t mmio_phys_addr; struct pcie_mbar mbar;
if (!pcie_probe(rom->pcie_bdf, rom->pcie_id)) { if (!pcie_probe(rom->pcie_bdf, rom->pcie_id)) {
return -EINVAL; return -EINVAL;
} }
mmio_phys_addr = pcie_get_mbar(rom->pcie_bdf, 0); pcie_get_mbar(rom->pcie_bdf, 0, &mbar);
pcie_set_cmd(rom->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true); pcie_set_cmd(rom->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true);
device_map(DEVICE_MMIO_RAM_PTR(dev), mmio_phys_addr, device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr,
0x1000, K_MEM_CACHE_NONE); mbar.size, K_MEM_CACHE_NONE);
} else } else
#endif #endif
{ {

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2019 Intel Corporation * Copyright (c) 2019 Intel Corporation
* Copyright (c) 2020 acontis technologies GmbH
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -46,26 +47,57 @@ void pcie_set_cmd(pcie_bdf_t bdf, uint32_t bits, bool on)
pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmdstat); pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmdstat);
} }
uintptr_t pcie_get_mbar(pcie_bdf_t bdf, unsigned int index) bool pcie_get_mbar(pcie_bdf_t bdf, unsigned int index, struct pcie_mbar *mbar)
{ {
uint32_t reg, bar; bool valid_bar = false;
uintptr_t addr = PCIE_CONF_BAR_NONE; uint32_t reg;
uintptr_t phys_addr = PCIE_CONF_BAR_NONE;
size_t size = 0;
reg = PCIE_CONF_BAR0; for (reg = PCIE_CONF_BAR0; reg <= PCIE_CONF_BAR5; reg++) {
for (bar = 0; bar < index && reg <= PCIE_CONF_BAR5; bar++) { uint32_t addr = pcie_conf_read(bdf, reg);
if (PCIE_CONF_BAR_64(pcie_conf_read(bdf, reg++))) {
/* skip useless bars and I/O Bars */
if (addr == 0xFFFFFFFFU || addr == 0x0U || PCIE_CONF_BAR_IO(addr)) {
continue;
}
if (index == 0) {
valid_bar = true;
break;
}
if (PCIE_CONF_BAR_64(addr)) {
reg++; reg++;
} }
index--;
} }
if (bar == index) { if (valid_bar) {
addr = pcie_conf_read(bdf, reg++); phys_addr = pcie_conf_read(bdf, reg);
if (IS_ENABLED(CONFIG_64BIT) && PCIE_CONF_BAR_64(addr)) { pcie_conf_write(bdf, reg, 0xFFFFFFFF);
addr |= ((uint64_t)pcie_conf_read(bdf, reg)) << 32; size = pcie_conf_read(bdf, reg);
pcie_conf_write(bdf, reg, (uint32_t)phys_addr);
if (IS_ENABLED(CONFIG_64BIT) && PCIE_CONF_BAR_64(phys_addr)) {
reg++;
phys_addr |= ((uint64_t)pcie_conf_read(bdf, reg)) << 32;
pcie_conf_write(bdf, reg, 0xFFFFFFFF);
size |= ((uint64_t)pcie_conf_read(bdf, reg)) << 32;
pcie_conf_write(bdf, reg, (uint32_t)((uint64_t)phys_addr >> 32));
}
size = PCIE_CONF_BAR_ADDR(size);
if (size) {
mbar->phys_addr = PCIE_CONF_BAR_ADDR(phys_addr);
mbar->size = size & ~(size-1);
} else {
valid_bar = false;
} }
} }
return PCIE_CONF_BAR_ADDR(addr); return valid_bar;
} }
/* The first bit is used to indicate whether the list of reserved interrupts /* The first bit is used to indicate whether the list of reserved interrupts

View file

@ -352,17 +352,17 @@ static int uart_ns16550_configure(const struct device *dev,
#ifndef UART_NS16550_ACCESS_IOPORT #ifndef UART_NS16550_ACCESS_IOPORT
#ifdef UART_NS16550_PCIE_ENABLED #ifdef UART_NS16550_PCIE_ENABLED
if (dev_cfg->pcie) { if (dev_cfg->pcie) {
uintptr_t phys; struct pcie_mbar mbar;
if (!pcie_probe(dev_cfg->pcie_bdf, dev_cfg->pcie_id)) { if (!pcie_probe(dev_cfg->pcie_bdf, dev_cfg->pcie_id)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
phys = pcie_get_mbar(dev_cfg->pcie_bdf, 0); pcie_get_mbar(dev_cfg->pcie_bdf, 0, &mbar);
pcie_set_cmd(dev_cfg->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true); pcie_set_cmd(dev_cfg->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true);
device_map(DEVICE_MMIO_RAM_PTR(dev), phys, 0x1000, device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr, mbar.size,
K_MEM_CACHE_NONE); K_MEM_CACHE_NONE);
} else } else
#endif /* UART_NS16550_PCIE_ENABLED */ #endif /* UART_NS16550_PCIE_ENABLED */

View file

@ -7,6 +7,7 @@
#ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_
#define ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_
#include <stddef.h>
#include <dt-bindings/pcie/pcie.h> #include <dt-bindings/pcie/pcie.h>
#include <zephyr/types.h> #include <zephyr/types.h>
@ -35,6 +36,11 @@ typedef uint32_t pcie_bdf_t;
*/ */
typedef uint32_t pcie_id_t; typedef uint32_t pcie_id_t;
struct pcie_mbar {
uintptr_t phys_addr;
size_t size;
};
/* /*
* These functions are arch-, board-, or SoC-specific. * These functions are arch-, board-, or SoC-specific.
*/ */
@ -74,15 +80,19 @@ extern bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id);
* @brief Get the nth MMIO address assigned to an endpoint. * @brief Get the nth MMIO address assigned to an endpoint.
* @param bdf the PCI(e) endpoint * @param bdf the PCI(e) endpoint
* @param index (0-based) index * @param index (0-based) index
* @return the address, or PCIE_CONF_BAR_NONE if nonexistent. * @param mbar Pointer to struct pcie_mbar
* @return true if the mbar was found, false otherwise
* *
* A PCI(e) endpoint has 0 or more memory-mapped regions. This function * 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 * allows the caller to enumerate them by calling with index=0..n. If
* PCIE_CONF_BAR_NONE is returned, there are no further regions. The indices * false is returned, there are no further regions. The indices
* are order-preserving with respect to the endpoint BARs: e.g., index 0 * are order-preserving with respect to the endpoint BARs (skips useless bars
* will return the lowest-numbered memory BAR on the endpoint. * and I/O Bars): e.g., index 0 will return the lowest-numbered valid memory BAR
* on the endpoint.
*/ */
extern uintptr_t pcie_get_mbar(pcie_bdf_t bdf, unsigned int index); extern bool pcie_get_mbar(pcie_bdf_t bdf,
unsigned int index,
struct pcie_mbar *mbar);
/** /**
* @brief Set or reset bits in the endpoint command/status register. * @brief Set or reset bits in the endpoint command/status register.