pci: pci_mvebu: Fix PCIe MEM and IO resources assignment and mbus mapping
Do not call pci_set_region() for resources which were not properly mapped. This prevents U-Boot to access unmapped memory space. Update MBUS_PCI_MEM_SIZE and MBUS_PCI_IO_SIZE macros to cover all PCIe MEM and IO ranges. Previously these macros covered only address ranges for the first PCIe port. Between MBUS_PCI_IO_BASE and MBUS_PCI_MEM_BASE there is space for six 128 MB long address ranges. So set MBUS_PCI_MEM_SIZE to value of 6*128 MB. Similarly set MBUS_PCI_IO_SIZE to 6*64 KB. Function resource_size() returns zero when start address is 0 and end address is -1. So set invalid resources to these values to indicate that resource has no mapping. Split global PCIe MEM and IO resources (defined by MBUS_PCI_*_* macros) into PCIe ports in mvebu_pcie_bind() function which allocates per-port based struct mvebu_pcie, instead of using global state variables mvebu_pcie_membase and mvebu_pcie_iobase. This makes pci_mvebu.c driver independent of global static variables (which store the state of allocation) and allows to bind and unbind the driver more times. Signed-off-by: Pali Rohár <pali@kernel.org> Signed-off-by: Marek Behún <marek.behun@nic.cz>
This commit is contained in:
parent
2ac06f3e66
commit
537b0142b0
2 changed files with 62 additions and 27 deletions
|
@ -74,10 +74,11 @@ enum {
|
|||
/*
|
||||
* Default Device Address MAP BAR values
|
||||
*/
|
||||
#define MBUS_PCI_MAX_PORTS 6
|
||||
#define MBUS_PCI_MEM_BASE MVEBU_SDRAM_SIZE_MAX
|
||||
#define MBUS_PCI_MEM_SIZE (128 << 20)
|
||||
#define MBUS_PCI_MEM_SIZE ((MBUS_PCI_MAX_PORTS * 128) << 20)
|
||||
#define MBUS_PCI_IO_BASE 0xF1100000
|
||||
#define MBUS_PCI_IO_SIZE (64 << 10)
|
||||
#define MBUS_PCI_IO_SIZE ((MBUS_PCI_MAX_PORTS * 64) << 10)
|
||||
#define MBUS_SPI_BASE 0xF4000000
|
||||
#define MBUS_SPI_SIZE (8 << 20)
|
||||
#define MBUS_DFX_BASE 0xF6000000
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
/* PCIe unit register offsets */
|
||||
#define SELECT(x, n) ((x >> n) & 1UL)
|
||||
|
@ -80,14 +81,6 @@ struct mvebu_pcie {
|
|||
u32 cfgcache[(0x3c - 0x10) / 4];
|
||||
};
|
||||
|
||||
/*
|
||||
* MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
|
||||
* into SoCs address space. Each controller will map 128M of MEM
|
||||
* and 64K of I/O space when registered.
|
||||
*/
|
||||
static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
|
||||
static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE;
|
||||
|
||||
static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
@ -433,26 +426,24 @@ static int mvebu_pcie_probe(struct udevice *dev)
|
|||
mvebu_pcie_set_local_bus_nr(pcie, 0);
|
||||
mvebu_pcie_set_local_dev_nr(pcie, 1);
|
||||
|
||||
pcie->mem.start = (u32)mvebu_pcie_membase;
|
||||
pcie->mem.end = pcie->mem.start + MBUS_PCI_MEM_SIZE - 1;
|
||||
mvebu_pcie_membase += MBUS_PCI_MEM_SIZE;
|
||||
|
||||
if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
|
||||
if (resource_size(&pcie->mem) &&
|
||||
mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
|
||||
(phys_addr_t)pcie->mem.start,
|
||||
resource_size(&pcie->mem))) {
|
||||
printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
|
||||
(u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem));
|
||||
pcie->mem.start = 0;
|
||||
pcie->mem.end = -1;
|
||||
}
|
||||
|
||||
pcie->io.start = (u32)mvebu_pcie_iobase;
|
||||
pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1;
|
||||
mvebu_pcie_iobase += MBUS_PCI_IO_SIZE;
|
||||
|
||||
if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
|
||||
if (resource_size(&pcie->io) &&
|
||||
mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
|
||||
(phys_addr_t)pcie->io.start,
|
||||
resource_size(&pcie->io))) {
|
||||
printf("PCIe unable to add mbus window for IO at %08x+%08x\n",
|
||||
(u32)pcie->io.start, (unsigned)resource_size(&pcie->io));
|
||||
pcie->io.start = 0;
|
||||
pcie->io.end = -1;
|
||||
}
|
||||
|
||||
/* Setup windows and configure host bridge */
|
||||
|
@ -461,13 +452,23 @@ static int mvebu_pcie_probe(struct udevice *dev)
|
|||
/* PCI memory space */
|
||||
pci_set_region(hose->regions + 0, pcie->mem.start,
|
||||
pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM);
|
||||
pci_set_region(hose->regions + 1,
|
||||
0, 0,
|
||||
gd->ram_size,
|
||||
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
|
||||
pci_set_region(hose->regions + 2, pcie->io.start,
|
||||
pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO);
|
||||
hose->region_count = 3;
|
||||
hose->region_count = 1;
|
||||
|
||||
if (resource_size(&pcie->mem)) {
|
||||
pci_set_region(hose->regions + hose->region_count,
|
||||
pcie->mem.start, pcie->mem.start,
|
||||
resource_size(&pcie->mem),
|
||||
PCI_REGION_MEM);
|
||||
hose->region_count++;
|
||||
}
|
||||
|
||||
if (resource_size(&pcie->io)) {
|
||||
pci_set_region(hose->regions + hose->region_count,
|
||||
pcie->io.start, pcie->io.start,
|
||||
resource_size(&pcie->io),
|
||||
PCI_REGION_IO);
|
||||
hose->region_count++;
|
||||
}
|
||||
|
||||
/* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */
|
||||
pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] =
|
||||
|
@ -628,6 +629,8 @@ static int mvebu_pcie_bind(struct udevice *parent)
|
|||
struct mvebu_pcie *pcie;
|
||||
struct uclass_driver *drv;
|
||||
struct udevice *dev;
|
||||
struct resource mem;
|
||||
struct resource io;
|
||||
ofnode subnode;
|
||||
|
||||
/* Lookup pci driver */
|
||||
|
@ -637,6 +640,11 @@ static int mvebu_pcie_bind(struct udevice *parent)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
mem.start = MBUS_PCI_MEM_BASE;
|
||||
mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1;
|
||||
io.start = MBUS_PCI_IO_BASE;
|
||||
io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1;
|
||||
|
||||
ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
|
||||
if (!ofnode_is_available(subnode))
|
||||
continue;
|
||||
|
@ -645,6 +653,32 @@ static int mvebu_pcie_bind(struct udevice *parent)
|
|||
if (!pcie)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
|
||||
* into SoCs address space. Each controller will map 128M of MEM
|
||||
* and 64K of I/O space when registered.
|
||||
*/
|
||||
|
||||
if (resource_size(&mem) >= SZ_128M) {
|
||||
pcie->mem.start = mem.start;
|
||||
pcie->mem.end = mem.start + SZ_128M - 1;
|
||||
mem.start += SZ_128M;
|
||||
} else {
|
||||
printf("PCIe unable to assign mbus window for mem\n");
|
||||
pcie->mem.start = 0;
|
||||
pcie->mem.end = -1;
|
||||
}
|
||||
|
||||
if (resource_size(&io) >= SZ_64K) {
|
||||
pcie->io.start = io.start;
|
||||
pcie->io.end = io.start + SZ_64K - 1;
|
||||
io.start += SZ_64K;
|
||||
} else {
|
||||
printf("PCIe unable to assign mbus window for io\n");
|
||||
pcie->io.start = 0;
|
||||
pcie->io.end = -1;
|
||||
}
|
||||
|
||||
/* Create child device UCLASS_PCI and bind it */
|
||||
device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode,
|
||||
&dev);
|
||||
|
|
Loading…
Reference in a new issue