Author: andrew
Date: Wed Jun 17 19:56:17 2020
New Revision: 362285
URL: https://svnweb.freebsd.org/changeset/base/362285

Log:
  Clean up the pci host generic driver
  
   - Support Prefetchable Memory.
   - Use the correct rman when allocating memory and ioports.
   - Translate PCI addresses in bus_alloc_resource to allow physical
     addresses that are different than pci addresses.
  
  Reviewed by:  Robert Crowston <crowston_protonmail.com>
  Sponsored by: Innovate UK
  Differential Revision:        https://reviews.freebsd.org/D25121

Modified:
  head/sys/dev/pci/pci_host_generic.c
  head/sys/dev/pci/pci_host_generic.h
  head/sys/dev/pci/pci_host_generic_acpi.c
  head/sys/dev/pci/pci_host_generic_fdt.c

Modified: head/sys/dev/pci/pci_host_generic.c
==============================================================================
--- head/sys/dev/pci/pci_host_generic.c Wed Jun 17 19:45:05 2020        
(r362284)
+++ head/sys/dev/pci/pci_host_generic.c Wed Jun 17 19:56:17 2020        
(r362285)
@@ -70,8 +70,11 @@ int
 pci_host_generic_core_attach(device_t dev)
 {
        struct generic_pcie_core_softc *sc;
+       uint64_t phys_base;
+       uint64_t pci_base;
+       uint64_t size;
        int error;
-       int rid;
+       int rid, tuple;
 
        sc = device_get_softc(dev);
        sc->dev = dev;
@@ -101,12 +104,23 @@ pci_host_generic_core_attach(device_t dev)
        sc->bst = rman_get_bustag(sc->res);
        sc->bsh = rman_get_bushandle(sc->res);
 
+       sc->has_pmem = false;
+       sc->pmem_rman.rm_type = RMAN_ARRAY;
+       sc->pmem_rman.rm_descr = "PCIe Prefetch Memory";
+
        sc->mem_rman.rm_type = RMAN_ARRAY;
        sc->mem_rman.rm_descr = "PCIe Memory";
+
        sc->io_rman.rm_type = RMAN_ARRAY;
        sc->io_rman.rm_descr = "PCIe IO window";
 
        /* Initialize rman and allocate memory regions */
+       error = rman_init(&sc->pmem_rman);
+       if (error) {
+               device_printf(dev, "rman_init() failed. error = %d\n", error);
+               return (error);
+       }
+
        error = rman_init(&sc->mem_rman);
        if (error) {
                device_printf(dev, "rman_init() failed. error = %d\n", error);
@@ -119,6 +133,39 @@ pci_host_generic_core_attach(device_t dev)
                return (error);
        }
 
+       for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
+               phys_base = sc->ranges[tuple].phys_base;
+               pci_base = sc->ranges[tuple].pci_base;
+               size = sc->ranges[tuple].size;
+               if (phys_base == 0 || size == 0)
+                       continue; /* empty range element */
+               switch (FLAG_TYPE(sc->ranges[tuple].flags)) {
+               case FLAG_TYPE_PMEM:
+                       sc->has_pmem = true;
+                       error = rman_manage_region(&sc->pmem_rman,
+                          phys_base, phys_base + size - 1);
+                       break;
+               case FLAG_TYPE_MEM:
+                       error = rman_manage_region(&sc->mem_rman,
+                          phys_base, phys_base + size - 1);
+                       break;
+               case FLAG_TYPE_IO:
+                       error = rman_manage_region(&sc->io_rman,
+                          phys_base, phys_base + size - 1);
+                       break;
+               default:
+                       continue;
+               }
+               if (error) {
+                       device_printf(dev, "rman_manage_region() failed."
+                                               "error = %d\n", error);
+                       rman_fini(&sc->pmem_rman);
+                       rman_fini(&sc->mem_rman);
+                       rman_fini(&sc->io_rman);
+                       return (error);
+               }
+       }
+
        return (0);
 }
 
@@ -236,13 +283,15 @@ generic_pcie_write_ivar(device_t dev, device_t child, 
 }
 
 static struct rman *
-generic_pcie_rman(struct generic_pcie_core_softc *sc, int type)
+generic_pcie_rman(struct generic_pcie_core_softc *sc, int type, int flags)
 {
 
        switch (type) {
        case SYS_RES_IOPORT:
                return (&sc->io_rman);
        case SYS_RES_MEMORY:
+               if (sc->has_pmem && (flags & RF_PREFETCHABLE) != 0)
+                       return (&sc->pmem_rman);
                return (&sc->mem_rman);
        default:
                break;
@@ -266,7 +315,7 @@ pci_host_generic_core_release_resource(device_t dev, d
        }
 #endif
 
-       rm = generic_pcie_rman(sc, type);
+       rm = generic_pcie_rman(sc, type, rman_get_flags(res));
        if (rm != NULL) {
                KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
                rman_release_resource(res);
@@ -282,6 +331,11 @@ pci_host_generic_core_alloc_resource(device_t dev, dev
        struct generic_pcie_core_softc *sc;
        struct resource *res;
        struct rman *rm;
+       uint64_t phys_base;
+       uint64_t pci_base;
+       uint64_t size;
+       int i, space;
+       bool found;
 
        sc = device_get_softc(dev);
 
@@ -292,11 +346,56 @@ pci_host_generic_core_alloc_resource(device_t dev, dev
        }
 #endif
 
-       rm = generic_pcie_rman(sc, type);
+       rm = generic_pcie_rman(sc, type, flags);
        if (rm == NULL)
                return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
                    type, rid, start, end, count, flags));
 
+       /* Translate the address from a PCI address to a physical address */
+       switch (type) {
+       case SYS_RES_IOPORT:
+       case SYS_RES_MEMORY:
+               found = false;
+               for (i = 0; i < MAX_RANGES_TUPLES; i++) {
+                       pci_base = sc->ranges[i].pci_base;
+                       phys_base = sc->ranges[i].phys_base;
+                       size = sc->ranges[i].size;
+
+                       if (start < pci_base || start >= pci_base + size)
+                               continue;
+
+                       switch (FLAG_TYPE(sc->ranges[i].flags)) {
+                       case FLAG_TYPE_MEM:
+                       case FLAG_TYPE_PMEM:
+                               space = SYS_RES_MEMORY;
+                               break;
+                       case FLAG_TYPE_IO:
+                               space = SYS_RES_IOPORT;
+                               break;
+                       default:
+                               space = -1;
+                               continue;
+                       }
+
+                       if (type == space) {
+                               start = start - pci_base + phys_base;
+                               end = end - pci_base + phys_base;
+                               found = true;
+                               break;
+                       }
+               }
+               if (!found) {
+                       device_printf(dev,
+                           "Failed to allocate %s resource %lx-%lx for %s\n",
+                           type == SYS_RES_IOPORT ? "IOPORT" : "MEMORY",
+                           start, end, device_get_nameunit(child));
+                       return (NULL);
+               }
+               break;
+       default:
+               break;
+       }
+
        if (bootverbose) {
                device_printf(dev,
                    "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
@@ -330,53 +429,15 @@ generic_pcie_activate_resource(device_t dev, device_t 
     int rid, struct resource *r)
 {
        struct generic_pcie_core_softc *sc;
-       uint64_t phys_base;
-       uint64_t pci_base;
-       uint64_t size;
-       int found;
        int res;
-       int i;
 
        sc = device_get_softc(dev);
 
        if ((res = rman_activate_resource(r)) != 0)
                return (res);
 
-       switch (type) {
-       case SYS_RES_IOPORT:
-       case SYS_RES_MEMORY:
-               found = 0;
-               for (i = 0; i < MAX_RANGES_TUPLES; i++) {
-                       pci_base = sc->ranges[i].pci_base;
-                       phys_base = sc->ranges[i].phys_base;
-                       size = sc->ranges[i].size;
-
-                       if ((rman_get_start(r) >= pci_base) && 
(rman_get_start(r) < (pci_base + size))) {
-                               found = 1;
-                               break;
-                       }
-               }
-               if (found) {
-                       rman_set_start(r, rman_get_start(r) - pci_base + 
phys_base);
-                       rman_set_end(r, rman_get_end(r) - pci_base + phys_base);
-                       res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
-                           child, type, rid, r);
-               } else {
-                       device_printf(dev,
-                           "Failed to activate %s resource\n",
-                           type == SYS_RES_IOPORT ? "IOPORT" : "MEMORY");
-                       res = ENXIO;
-               }
-               break;
-       case SYS_RES_IRQ:
-               res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child,
-                   type, rid, r);
-               break;
-       default:
-               break;
-       }
-
-       return (res);
+       return (BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type,
+           rid, r));
 }
 
 static int
@@ -416,7 +477,7 @@ generic_pcie_adjust_resource(device_t dev, device_t ch
                    end));
 #endif
 
-       rm = generic_pcie_rman(sc, type);
+       rm = generic_pcie_rman(sc, type, rman_get_flags(res));
        if (rm != NULL)
                return (rman_adjust_resource(res, start, end));
        return (bus_generic_adjust_resource(dev, child, type, res, start, end));

Modified: head/sys/dev/pci/pci_host_generic.h
==============================================================================
--- head/sys/dev/pci/pci_host_generic.h Wed Jun 17 19:45:05 2020        
(r362284)
+++ head/sys/dev/pci/pci_host_generic.h Wed Jun 17 19:56:17 2020        
(r362285)
@@ -59,14 +59,20 @@ struct pcie_range {
        uint64_t        phys_base;
        uint64_t        size;
        uint64_t        flags;
-#define        FLAG_IO         (1 << 0)
-#define        FLAG_MEM        (1 << 1)
+#define        FLAG_TYPE(x)            ((x) & FLAG_TYPE_MASK)
+#define        FLAG_TYPE_MASK          0x3
+#define        FLAG_TYPE_INVALID       0x0
+#define        FLAG_TYPE_IO            0x1
+#define        FLAG_TYPE_MEM           0x2
+#define        FLAG_TYPE_PMEM          0x3
 };
 
 struct generic_pcie_core_softc {
        struct pcie_range       ranges[MAX_RANGES_TUPLES];
        int                     nranges;
        int                     coherent;
+       bool                    has_pmem;
+       struct rman             pmem_rman;
        struct rman             mem_rman;
        struct rman             io_rman;
        struct resource         *res;

Modified: head/sys/dev/pci/pci_host_generic_acpi.c
==============================================================================
--- head/sys/dev/pci/pci_host_generic_acpi.c    Wed Jun 17 19:45:05 2020        
(r362284)
+++ head/sys/dev/pci/pci_host_generic_acpi.c    Wed Jun 17 19:56:17 2020        
(r362285)
@@ -159,9 +159,9 @@ pci_host_generic_acpi_parse_resource(ACPI_RESOURCE *re
                sc->base.ranges[r].phys_base = min + off;
                sc->base.ranges[r].size = max - min + 1;
                if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE)
-                       sc->base.ranges[r].flags |= FLAG_MEM;
+                       sc->base.ranges[r].flags |= FLAG_TYPE_MEM;
                else if (res->Data.Address.ResourceType == ACPI_IO_RANGE)
-                       sc->base.ranges[r].flags |= FLAG_IO;
+                       sc->base.ranges[r].flags |= FLAG_TYPE_IO;
                sc->base.nranges++;
        } else if (res->Data.Address.ResourceType == ACPI_BUS_NUMBER_RANGE) {
                sc->base.bus_start = min;
@@ -234,12 +234,8 @@ pci_host_generic_acpi_init(device_t dev)
 {
        struct generic_pcie_acpi_softc *sc;
        ACPI_HANDLE handle;
-       uint64_t phys_base;
-       uint64_t pci_base;
-       uint64_t size;
        ACPI_STATUS status;
        int error;
-       int tuple;
 
        sc = device_get_softc(dev);
        handle = acpi_get_handle(dev);
@@ -278,29 +274,6 @@ pci_host_generic_acpi_init(device_t dev)
        error = pci_host_generic_core_attach(dev);
        if (error != 0)
                return (error);
-
-       for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
-               phys_base = sc->base.ranges[tuple].phys_base;
-               pci_base = sc->base.ranges[tuple].pci_base;
-               size = sc->base.ranges[tuple].size;
-               if (phys_base == 0 || size == 0)
-                       continue; /* empty range element */
-               if (sc->base.ranges[tuple].flags & FLAG_MEM) {
-                       error = rman_manage_region(&sc->base.mem_rman,
-                          pci_base, pci_base + size - 1);
-               } else if (sc->base.ranges[tuple].flags & FLAG_IO) {
-                       error = rman_manage_region(&sc->base.io_rman,
-                          pci_base + PCI_IO_WINDOW_OFFSET,
-                          pci_base + PCI_IO_WINDOW_OFFSET + size - 1);
-               } else
-                       continue;
-               if (error) {
-                       device_printf(dev, "rman_manage_region() failed."
-                                               "error = %d\n", error);
-                       rman_fini(&sc->base.mem_rman);
-                       return (error);
-               }
-       }
 
        return (0);
 }

Modified: head/sys/dev/pci/pci_host_generic_fdt.c
==============================================================================
--- head/sys/dev/pci/pci_host_generic_fdt.c     Wed Jun 17 19:45:05 2020        
(r362284)
+++ head/sys/dev/pci/pci_host_generic_fdt.c     Wed Jun 17 19:56:17 2020        
(r362285)
@@ -123,12 +123,8 @@ int
 pci_host_generic_attach(device_t dev)
 {
        struct generic_pcie_fdt_softc *sc;
-       uint64_t phys_base;
-       uint64_t pci_base;
-       uint64_t size;
        phandle_t node;
        int error;
-       int tuple;
 
        sc = device_get_softc(dev);
 
@@ -157,28 +153,6 @@ pci_host_generic_attach(device_t dev)
        if (error != 0)
                return (error);
 
-       for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
-               phys_base = sc->base.ranges[tuple].phys_base;
-               pci_base = sc->base.ranges[tuple].pci_base;
-               size = sc->base.ranges[tuple].size;
-               if (phys_base == 0 || size == 0)
-                       continue; /* empty range element */
-               if (sc->base.ranges[tuple].flags & FLAG_MEM) {
-                       error = rman_manage_region(&sc->base.mem_rman,
-                           pci_base, pci_base + size - 1);
-               } else if (sc->base.ranges[tuple].flags & FLAG_IO) {
-                       error = rman_manage_region(&sc->base.io_rman,
-                           pci_base, pci_base + size - 1);
-               } else
-                       continue;
-               if (error) {
-                       device_printf(dev, "rman_manage_region() failed."
-                                               "error = %d\n", error);
-                       rman_fini(&sc->base.mem_rman);
-                       return (error);
-               }
-       }
-
        ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t));
 
        device_add_child(dev, "pci", -1);
@@ -221,9 +195,9 @@ parse_pci_mem_ranges(device_t dev, struct generic_pcie
                attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \
                                                        SPACE_CODE_MASK;
                if (attributes == SPACE_CODE_IO_SPACE) {
-                       sc->ranges[i].flags |= FLAG_IO;
+                       sc->ranges[i].flags |= FLAG_TYPE_IO;
                } else {
-                       sc->ranges[i].flags |= FLAG_MEM;
+                       sc->ranges[i].flags |= FLAG_TYPE_MEM;
                }
 
                sc->ranges[i].pci_base = 0;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to