]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
pci: pci_mvebu: Fix PCIe MEM and IO resources assignment and mbus mapping
authorPali Rohár <pali@kernel.org>
Tue, 21 Dec 2021 11:20:13 +0000 (12:20 +0100)
committerStefan Roese <sr@denx.de>
Fri, 14 Jan 2022 06:47:57 +0000 (07:47 +0100)
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>
arch/arm/mach-mvebu/include/mach/cpu.h
drivers/pci/pci_mvebu.c

index a7a62c7e7d53b49d6c8b30d231757a015fdd3499..b99d86a87a030367abf0d1ffe95dfa3f25e90399 100644 (file)
@@ -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
index 18f79d249c7f081c5ac167806cd697cc9563c896..0ce602b435fb1291722ebf11ed201ba7ce27839f 100644 (file)
@@ -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);