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)
{
#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 */

View file

@ -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);
...
}

View file

@ -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 */

View file

@ -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
{

View file

@ -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

View file

@ -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 */

View file

@ -7,6 +7,7 @@
#ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_
#define ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_
#include <stddef.h>
#include <dt-bindings/pcie/pcie.h>
#include <zephyr/types.h>
@ -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.