From 3c8e98cb39fa17f3152d76a4a04c7402939d5d31 Mon Sep 17 00:00:00 2001 From: Maximilian Bachmann Date: Thu, 5 Nov 2020 00:15:25 +0100 Subject: [PATCH] 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 --- arch/x86/core/early_serial.c | 10 +++--- doc/reference/drivers/index.rst | 6 ++-- drivers/ethernet/eth_e1000.c | 8 ++--- drivers/i2c/i2c_dw.c | 8 ++--- drivers/pcie/host/pcie.c | 54 ++++++++++++++++++++++++++------- drivers/serial/uart_ns16550.c | 6 ++-- include/drivers/pcie/pcie.h | 20 +++++++++--- 7 files changed, 76 insertions(+), 36 deletions(-) diff --git a/arch/x86/core/early_serial.c b/arch/x86/core/early_serial.c index 705cabb6447..d828e7cf115 100644 --- a/arch/x86/core/early_serial.c +++ b/arch/x86/core/early_serial.c @@ -79,15 +79,15 @@ int arch_printk_char_out(int c) void z_x86_early_serial_init(void) { #if defined(DEVICE_MMIO_IS_IN_RAM) && !defined(UART_NS16550_ACCESS_IOPORT) - uintptr_t phys; - #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); + device_map(&mmio, mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE); #else - phys = X86_SOC_EARLY_SERIAL_MMIO8_ADDR; + device_map(&mmio, X86_SOC_EARLY_SERIAL_MMIO8_ADDR, 0x1000, K_MEM_CACHE_NONE); #endif - device_map(&mmio, phys, 0x1000, K_MEM_CACHE_NONE); + #endif /* DEVICE_MMIO_IS_IN_RAM */ OUT(REG_IER, IER_DISABLE); /* Disable interrupts */ diff --git a/doc/reference/drivers/index.rst b/doc/reference/drivers/index.rst index 9df3d2e0292..2765402928b 100644 --- a/doc/reference/drivers/index.rst +++ b/doc/reference/drivers/index.rst @@ -584,10 +584,10 @@ may be used directly: void some_init_code(...) { ... - uintptr_t phys_addr = pcie_get_mbar(...); - size_t size = ... + struct pcie_mbar mbar; + 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); ... } diff --git a/drivers/ethernet/eth_e1000.c b/drivers/ethernet/eth_e1000.c index 3430d13e70c..2c781d76644 100644 --- a/drivers/ethernet/eth_e1000.c +++ b/drivers/ethernet/eth_e1000.c @@ -217,20 +217,18 @@ int e1000_probe(const struct device *device) const pcie_bdf_t bdf = PCIE_BDF(0, 3, 0); struct e1000_dev *dev = device->data; uint32_t ral, rah; - uintptr_t phys_addr; - size_t size; + struct pcie_mbar mbar; if (!pcie_probe(bdf, PCIE_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_I82540EM))) { return -ENODEV; } - phys_addr = pcie_get_mbar(bdf, 0); + pcie_get_mbar(bdf, 0, &mbar); pcie_set_cmd(bdf, PCIE_CONF_CMDSTAT_MEM | 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); /* Setup TX descriptor */ diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index 2321bea863b..fc2b164936f 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -611,17 +611,17 @@ static int i2c_dw_initialize(const struct device *dev) #ifdef I2C_DW_PCIE_ENABLED if (rom->pcie) { - uintptr_t mmio_phys_addr; + struct pcie_mbar mbar; if (!pcie_probe(rom->pcie_bdf, rom->pcie_id)) { 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); - device_map(DEVICE_MMIO_RAM_PTR(dev), mmio_phys_addr, - 0x1000, K_MEM_CACHE_NONE); + device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr, + mbar.size, K_MEM_CACHE_NONE); } else #endif { diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 842dc948a0c..9353d9266ca 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Intel Corporation + * Copyright (c) 2020 acontis technologies GmbH * * 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); } -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; - uintptr_t addr = PCIE_CONF_BAR_NONE; + bool valid_bar = false; + uint32_t reg; + uintptr_t phys_addr = PCIE_CONF_BAR_NONE; + size_t size = 0; - reg = PCIE_CONF_BAR0; - for (bar = 0; bar < index && reg <= PCIE_CONF_BAR5; bar++) { - if (PCIE_CONF_BAR_64(pcie_conf_read(bdf, reg++))) { + for (reg = PCIE_CONF_BAR0; reg <= PCIE_CONF_BAR5; reg++) { + uint32_t addr = 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++; } + + index--; } - 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; + if (valid_bar) { + phys_addr = pcie_conf_read(bdf, reg); + pcie_conf_write(bdf, reg, 0xFFFFFFFF); + 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 diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 2951ab719ab..ac74c08e93d 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -352,17 +352,17 @@ static int uart_ns16550_configure(const struct device *dev, #ifndef UART_NS16550_ACCESS_IOPORT #ifdef UART_NS16550_PCIE_ENABLED if (dev_cfg->pcie) { - uintptr_t phys; + struct pcie_mbar mbar; if (!pcie_probe(dev_cfg->pcie_bdf, dev_cfg->pcie_id)) { ret = -EINVAL; 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); - 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); } else #endif /* UART_NS16550_PCIE_ENABLED */ diff --git a/include/drivers/pcie/pcie.h b/include/drivers/pcie/pcie.h index 1814a5f90a8..7397bee2098 100644 --- a/include/drivers/pcie/pcie.h +++ b/include/drivers/pcie/pcie.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ +#include #include #include @@ -35,6 +36,11 @@ typedef uint32_t pcie_bdf_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. */ @@ -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. * @param bdf the PCI(e) endpoint * @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 * 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 - * are order-preserving with respect to the endpoint BARs: e.g., index 0 - * will return the lowest-numbered memory BAR on the endpoint. + * false is returned, there are no further regions. The indices + * are order-preserving with respect to the endpoint BARs (skips useless bars + * 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.