git: 03713f805a91 - main - pci_host_generic: Tolerate range resource allocation failures

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Tue, 09 Apr 2024 21:56:05 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=03713f805a91749eabcfb2e23e86489b2d4034df

commit 03713f805a91749eabcfb2e23e86489b2d4034df
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-04-09 21:55:40 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-04-09 21:55:40 +0000

    pci_host_generic: Tolerate range resource allocation failures
    
    QEMU for armv7 includes a PCI memory range whose CPU address is
    greater than 4GB.  This falls outside the range of armv7's global
    mem_rman used by the nexus driver.  As a result, pcib0 fails to
    attach blocking all PCI devices.
    
    Instead, change the driver to be a bit more tolerant.  If allocating a
    resource for a range fails, don't fail attaching the entire driver,
    but do skip adding the associated PCI range to the relevant rman in
    the pcib driver.  This will prevent child devices from using BARs that
    allocate from this range.  In the case of QEMU on armv7 devices can
    still allocate from an earlier PCI memory range that is within the
    32-bit address space (and in fact none of the firmware-assigned memory
    BARs use addresses from the upper range).
    
    While here, reorder the operations on I/O ranges a bit: 1) print the
    range under bootverbose first (rather than last) so that the range is
    printed before any relevant errors for the range, 2) move
    rman_manage_region last after the parent resource has been set and
    allocated.
    
    Reported by:    markj, Jenkins
    Reviewed by:    markj
    Fixes:          d79b6b8ec267 pci_host_generic: Don't rewrite resource start address for translation
    Differential Revision:  https://reviews.freebsd.org/D44698
---
 sys/dev/pci/pci_host_generic.c | 55 ++++++++++++------------------------------
 1 file changed, 16 insertions(+), 39 deletions(-)

diff --git a/sys/dev/pci/pci_host_generic.c b/sys/dev/pci/pci_host_generic.c
index 0bdc121f9727..82ed51460621 100644
--- a/sys/dev/pci/pci_host_generic.c
+++ b/sys/dev/pci/pci_host_generic.c
@@ -80,6 +80,7 @@ pci_host_generic_core_attach(device_t dev)
 	struct resource_map map;
 #endif
 	struct generic_pcie_core_softc *sc;
+	struct rman *rm;
 	uint64_t phys_base;
 	uint64_t pci_base;
 	uint64_t size;
@@ -183,75 +184,51 @@ pci_host_generic_core_attach(device_t dev)
 			range_descr = "prefetch";
 			flags = RF_PREFETCHABLE;
 			type = SYS_RES_MEMORY;
-			error = rman_manage_region(&sc->pmem_rman,
-			   pci_base, pci_base + size - 1);
+			rm = &sc->pmem_rman;
 			break;
 		case FLAG_TYPE_MEM:
 			range_descr = "memory";
 			flags = 0;
 			type = SYS_RES_MEMORY;
-			error = rman_manage_region(&sc->mem_rman,
-			   pci_base, pci_base + size - 1);
+			rm = &sc->mem_rman;
 			break;
 		case FLAG_TYPE_IO:
 			range_descr = "I/O port";
 			flags = 0;
 			type = SYS_RES_IOPORT;
-			error = rman_manage_region(&sc->io_rman,
-			   pci_base, pci_base + size - 1);
+			rm = &sc->io_rman;
 			break;
 		default:
 			continue;
 		}
-		if (error) {
-			device_printf(dev, "rman_manage_region() failed."
-						"error = %d\n", error);
-			goto err_rman_manage;
-		}
+		if (bootverbose)
+			device_printf(dev,
+			    "PCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Type: %s\n",
+			    pci_base, phys_base, size, range_descr);
 		error = bus_set_resource(dev, type, rid, phys_base, size);
 		if (error != 0) {
 			device_printf(dev,
 			    "failed to set resource for range %d: %d\n", tuple,
 			    error);
-			goto err_rman_manage;
+			continue;
 		}
 		sc->ranges[tuple].res = bus_alloc_resource_any(dev, type, &rid,
 		    RF_ACTIVE | RF_UNMAPPED | flags);
 		if (sc->ranges[tuple].res == NULL) {
 			device_printf(dev,
 			    "failed to allocate resource for range %d\n", tuple);
-			error = ENXIO;
-			goto err_rman_manage;
+			continue;
+		}
+		error = rman_manage_region(rm, pci_base, pci_base + size - 1);
+		if (error) {
+			device_printf(dev, "rman_manage_region() failed."
+						"error = %d\n", error);
+			continue;
 		}
-		if (bootverbose)
-			device_printf(dev,
-			    "PCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Type: %s\n",
-			    pci_base, phys_base, size, range_descr);
 	}
 
 	return (0);
 
-err_rman_manage:
-	for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
-		if (sc->ranges[tuple].size == 0)
-			continue; /* empty range element */
-		switch (FLAG_TYPE(sc->ranges[tuple].flags)) {
-		case FLAG_TYPE_PMEM:
-		case FLAG_TYPE_MEM:
-			type = SYS_RES_MEMORY;
-			break;
-		case FLAG_TYPE_IO:
-			type = SYS_RES_IOPORT;
-			break;
-		default:
-			continue;
-		}
-		if (sc->ranges[tuple].res != NULL)
-			bus_release_resource(dev, type, tuple + 1,
-			    sc->ranges[tuple].res);
-		bus_delete_resource(dev, type, tuple + 1);
-	}
-	rman_fini(&sc->io_rman);
 err_io_rman:
 	rman_fini(&sc->mem_rman);
 err_mem_rman: