git: d79b6b8ec267 - main - pci_host_generic: Don't rewrite resource start address for translation

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 14 Feb 2024 22:52:46 UTC
The branch main has been updated by jhb:

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

commit d79b6b8ec267e7eef6e07cf4245159705e24acd5
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-02-14 22:07:33 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-02-14 22:07:33 +0000

    pci_host_generic: Don't rewrite resource start address for translation
    
    Allocate resources from the parent device for decoded physical address
    ranges.  When child resources suballocated from rman's are mapped,
    translate those mapping requests into a mapping request of the
    associated physical address range in a bus_map_resource method.
    
    While here, convert generic_pcie_rman to a bus_get_rman method and use
    bus_generic_rman_* for operations on child resources.
    
    Factor out a generic_pcie_containing_range to share logic between
    bus_translate_resource and bus_*map_resource.
    
    Reviewed by:    imp
    Differential Revision:  https://reviews.freebsd.org/D43894
---
 sys/dev/pci/pci_host_generic.c | 366 ++++++++++++++++++++++++++---------------
 sys/dev/pci/pci_host_generic.h |   1 +
 2 files changed, 235 insertions(+), 132 deletions(-)

diff --git a/sys/dev/pci/pci_host_generic.c b/sys/dev/pci/pci_host_generic.c
index 02ca010a14d7..45a478634d20 100644
--- a/sys/dev/pci/pci_host_generic.c
+++ b/sys/dev/pci/pci_host_generic.c
@@ -85,7 +85,7 @@ pci_host_generic_core_attach(device_t dev)
 	uint64_t size;
 	char buf[64];
 	int domain, error;
-	int rid, tuple;
+	int flags, rid, tuple, type;
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
@@ -173,19 +173,26 @@ pci_host_generic_core_attach(device_t dev)
 		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)
+		rid = tuple + 1;
+		if (size == 0)
 			continue; /* empty range element */
 		switch (FLAG_TYPE(sc->ranges[tuple].flags)) {
 		case FLAG_TYPE_PMEM:
 			sc->has_pmem = true;
+			flags = RF_PREFETCHABLE;
+			type = SYS_RES_MEMORY;
 			error = rman_manage_region(&sc->pmem_rman,
 			   pci_base, pci_base + size - 1);
 			break;
 		case FLAG_TYPE_MEM:
+			flags = 0;
+			type = SYS_RES_MEMORY;
 			error = rman_manage_region(&sc->mem_rman,
 			   pci_base, pci_base + size - 1);
 			break;
 		case FLAG_TYPE_IO:
+			flags = 0;
+			type = SYS_RES_IOPORT;
 			error = rman_manage_region(&sc->io_rman,
 			   pci_base, pci_base + size - 1);
 			break;
@@ -197,11 +204,44 @@ pci_host_generic_core_attach(device_t dev)
 						"error = %d\n", error);
 			goto err_rman_manage;
 		}
+		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;
+		}
+		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);
+			goto err_rman_manage;
+		}
 	}
 
 	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);
@@ -222,7 +262,7 @@ int
 pci_host_generic_core_detach(device_t dev)
 {
 	struct generic_pcie_core_softc *sc;
-	int error;
+	int error, tuple, type;
 
 	sc = device_get_softc(dev);
 
@@ -230,6 +270,25 @@ pci_host_generic_core_detach(device_t dev)
 	if (error != 0)
 		return (error);
 
+	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);
 	rman_fini(&sc->mem_rman);
 	rman_fini(&sc->pmem_rman);
@@ -349,8 +408,9 @@ generic_pcie_write_ivar(device_t dev, device_t child, int index,
 }
 
 static struct rman *
-generic_pcie_rman(struct generic_pcie_core_softc *sc, int type, int flags)
+generic_pcie_get_rman(device_t dev, int type, u_int flags)
 {
+	struct generic_pcie_core_softc *sc = device_get_softc(dev);
 
 	switch (type) {
 	case SYS_RES_IOPORT:
@@ -371,8 +431,6 @@ pci_host_generic_core_release_resource(device_t dev, device_t child, int type,
     int rid, struct resource *res)
 {
 	struct generic_pcie_core_softc *sc;
-	struct rman *rm;
-	int error;
 
 	sc = device_get_softc(dev);
 
@@ -381,76 +439,79 @@ pci_host_generic_core_release_resource(device_t dev, device_t child, int type,
 		return (pci_domain_release_bus(sc->ecam, child, rid, res));
 	}
 #endif
+	return (bus_generic_rman_release_resource(dev, child, type, rid, res));
+}
 
-	rm = generic_pcie_rman(sc, type, rman_get_flags(res));
-	if (rm != NULL) {
-		KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
-		if (rman_get_flags(res) & RF_ACTIVE) {
-			error = bus_deactivate_resource(child, type, rid, res);
-			if (error)
-				return (error);
-		}
-		return (rman_release_resource(res));
+static struct pcie_range *
+generic_pcie_containing_range(device_t dev, int type, rman_res_t start,
+    rman_res_t end)
+{
+	struct generic_pcie_core_softc *sc = device_get_softc(dev);
+	uint64_t pci_base;
+	uint64_t size;
+	int i, space;
+
+	switch (type) {
+	case SYS_RES_IOPORT:
+	case SYS_RES_MEMORY:
+		break;
+	default:
+		return (NULL);
 	}
 
-	return (bus_generic_release_resource(dev, child, type, rid, res));
+	for (i = 0; i < MAX_RANGES_TUPLES; i++) {
+		pci_base = sc->ranges[i].pci_base;
+		size = sc->ranges[i].size;
+		if (size == 0)
+			continue; /* empty range element */
+
+		if (start < pci_base || end >= 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:
+			continue;
+		}
+
+		if (type == space)
+			return (&sc->ranges[i]);
+	}
+	return (NULL);
 }
 
 static int
 generic_pcie_translate_resource_common(device_t dev, int type, rman_res_t start,
     rman_res_t end, rman_res_t *new_start, rman_res_t *new_end)
 {
-	struct generic_pcie_core_softc *sc;
-	uint64_t phys_base;
-	uint64_t pci_base;
-	uint64_t size;
-	int i, space;
-	bool found;
+	struct pcie_range *range;
 
-	sc = device_get_softc(dev);
 	/* 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) {
-				*new_start = start - pci_base + phys_base;
-				*new_end = end - pci_base + phys_base;
-				found = true;
-				break;
-			}
+		range = generic_pcie_containing_range(dev, type, start, end);
+		if (range == NULL)
+			return (ENOENT);
+		if (range != NULL) {
+			*new_start = start - range->pci_base + range->phys_base;
+			*new_end = end - range->pci_base + range->phys_base;
 		}
 		break;
 	default:
 		/* No translation for non-memory types */
 		*new_start = start;
 		*new_end = end;
-		found = true;
 		break;
 	}
 
-	return (found ? 0 : ENOENT);
+	return (0);
 }
 
 static int
@@ -469,48 +530,32 @@ pci_host_generic_core_alloc_resource(device_t dev, device_t child, int type,
 {
 	struct generic_pcie_core_softc *sc;
 	struct resource *res;
-	struct rman *rm;
 
 	sc = device_get_softc(dev);
 
+	switch (type) {
 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
-	if (type == PCI_RES_BUS) {
-		return (pci_domain_alloc_bus(sc->ecam, child, rid, start, end,
-		    count, flags));
-	}
+	case PCI_RES_BUS:
+		res = pci_domain_alloc_bus(sc->ecam, child, rid, start, end,
+		    count, flags);
+		break;
 #endif
-
-	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));
-
-	if (bootverbose) {
-		device_printf(dev,
-		    "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
-		    start, end, count);
+	case SYS_RES_IOPORT:
+	case SYS_RES_MEMORY:
+		res = bus_generic_rman_alloc_resource(dev, child, type, rid,
+		    start, end, count, flags);
+		break;
+	default:
+		res = bus_generic_alloc_resource(dev, child, type, rid, start,
+		    end, count, flags);
+		break;
+	}
+	if (res == NULL) {
+		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
+		    "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
+		    __func__, type, *rid, start, end, count, flags);
 	}
-
-	res = rman_reserve_resource(rm, start, end, count, flags, child);
-	if (res == NULL)
-		goto fail;
-
-	rman_set_rid(res, *rid);
-
-	if (flags & RF_ACTIVE)
-		if (bus_activate_resource(child, type, *rid, res)) {
-			rman_release_resource(res);
-			goto fail;
-		}
-
 	return (res);
-
-fail:
-	device_printf(dev, "%s FAIL: type=%d, rid=%d, "
-	    "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
-	    __func__, type, *rid, start, end, count, flags);
-
-	return (NULL);
 }
 
 static int
@@ -519,33 +564,22 @@ generic_pcie_activate_resource(device_t dev, device_t child, int type,
 {
 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
 	struct generic_pcie_core_softc *sc;
-#endif
-	rman_res_t start, end;
-	int res;
 
-#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
 	sc = device_get_softc(dev);
-	if (type == PCI_RES_BUS) {
+#endif
+	switch (type) {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	case PCI_RES_BUS:
 		return (pci_domain_activate_bus(sc->ecam, child, rid, r));
-	}
 #endif
-
-	if ((res = rman_activate_resource(r)) != 0)
-		return (res);
-
-	start = rman_get_start(r);
-	end = rman_get_end(r);
-	res = generic_pcie_translate_resource_common(dev, type, start, end,
-	    &start, &end);
-	if (res != 0) {
-		rman_deactivate_resource(r);
-		return (res);
+	case SYS_RES_IOPORT:
+	case SYS_RES_MEMORY:
+		return (bus_generic_rman_activate_resource(dev, child, type,
+		    rid, r));
+	default:
+		return (bus_generic_activate_resource(dev, child, type, rid,
+		    r));
 	}
-	rman_set_start(r, start);
-	rman_set_end(r, end);
-
-	return (BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type,
-	    rid, r));
 }
 
 static int
@@ -554,50 +588,115 @@ generic_pcie_deactivate_resource(device_t dev, device_t child, int type,
 {
 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
 	struct generic_pcie_core_softc *sc;
-#endif
-	int res;
 
-#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
 	sc = device_get_softc(dev);
-	if (type == PCI_RES_BUS) {
-		return (pci_domain_deactivate_bus(sc->ecam, child, rid, r));
-	}
 #endif
-	if ((res = rman_deactivate_resource(r)) != 0)
-		return (res);
-
 	switch (type) {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	case PCI_RES_BUS:
+		return (pci_domain_deactivate_bus(sc->ecam, child, rid, r));
+#endif
 	case SYS_RES_IOPORT:
 	case SYS_RES_MEMORY:
-	case SYS_RES_IRQ:
-		res = BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), child,
-		    type, rid, r);
-		break;
+		return (bus_generic_rman_deactivate_resource(dev, child, type,
+		    rid, r));
 	default:
-		break;
+		return (bus_generic_deactivate_resource(dev, child, type, rid,
+		    r));
 	}
-
-	return (res);
 }
 
 static int
 generic_pcie_adjust_resource(device_t dev, device_t child, int type,
     struct resource *res, rman_res_t start, rman_res_t end)
 {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
 	struct generic_pcie_core_softc *sc;
-	struct rman *rm;
 
 	sc = device_get_softc(dev);
+#endif
+	switch (type) {
 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
-	if (type == PCI_RES_BUS)
+	case PCI_RES_BUS:
 		return (pci_domain_adjust_bus(sc->ecam, child, res, start,
 		    end));
 #endif
+	case SYS_RES_IOPORT:
+	case SYS_RES_MEMORY:
+		return (bus_generic_rman_adjust_resource(dev, child, type, res,
+		    start, end));
+	default:
+		return (bus_generic_adjust_resource(dev, child, type, res,
+		    start, end));
+	}
+}
+
+static int
+generic_pcie_map_resource(device_t dev, device_t child, int type,
+    struct resource *r, struct resource_map_request *argsp,
+    struct resource_map *map)
+{
+	struct resource_map_request args;
+	struct pcie_range *range;
+	rman_res_t length, start;
+	int error;
+
+	switch (type) {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	case PCI_RES_BUS:
+		return (EINVAL);
+#endif
+	case SYS_RES_IOPORT:
+	case SYS_RES_MEMORY:
+		break;
+	default:
+		return (bus_generic_map_resource(dev, child, type, r, argsp,
+		    map));
+	}
 
-	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));
+	/* Resources must be active to be mapped. */
+	if (!(rman_get_flags(r) & RF_ACTIVE))
+		return (ENXIO);
+
+	resource_init_map_request(&args);
+	error = resource_validate_map_request(r, argsp, &args, &start, &length);
+	if (error)
+		return (error);
+
+	range = generic_pcie_containing_range(dev, type, rman_get_start(r),
+	    rman_get_end(r));
+	if (range == NULL || range->res == NULL)
+		return (ENOENT);
+
+	args.offset = start - range->pci_base;
+	args.length = length;
+	return (bus_generic_map_resource(dev, child, type, range->res, &args,
+	    map));
+}
+
+static int
+generic_pcie_unmap_resource(device_t dev, device_t child, int type,
+    struct resource *r, struct resource_map *map)
+{
+	struct pcie_range *range;
+
+	switch (type) {
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+	case PCI_RES_BUS:
+		return (EINVAL);
+#endif
+	case SYS_RES_IOPORT:
+	case SYS_RES_MEMORY:
+		range = generic_pcie_containing_range(dev, type,
+		    rman_get_start(r), rman_get_end(r));
+		if (range == NULL || range->res == NULL)
+			return (ENOENT);
+		r = range->res;
+		break;
+	default:
+		break;
+	}
+	return (bus_generic_unmap_resource(dev, child, type, r, map));
 }
 
 static bus_dma_tag_t
@@ -613,6 +712,7 @@ static device_method_t generic_pcie_methods[] = {
 	DEVMETHOD(device_attach,		pci_host_generic_core_attach),
 	DEVMETHOD(device_detach,		pci_host_generic_core_detach),
 
+	DEVMETHOD(bus_get_rman,			generic_pcie_get_rman),
 	DEVMETHOD(bus_read_ivar,		generic_pcie_read_ivar),
 	DEVMETHOD(bus_write_ivar,		generic_pcie_write_ivar),
 	DEVMETHOD(bus_alloc_resource,		pci_host_generic_core_alloc_resource),
@@ -621,6 +721,8 @@ static device_method_t generic_pcie_methods[] = {
 	DEVMETHOD(bus_deactivate_resource,	generic_pcie_deactivate_resource),
 	DEVMETHOD(bus_release_resource,		pci_host_generic_core_release_resource),
 	DEVMETHOD(bus_translate_resource,	generic_pcie_translate_resource),
+	DEVMETHOD(bus_map_resource,		generic_pcie_map_resource),
+	DEVMETHOD(bus_unmap_resource,		generic_pcie_unmap_resource),
 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
 
diff --git a/sys/dev/pci/pci_host_generic.h b/sys/dev/pci/pci_host_generic.h
index 8e72ac6e5cef..2d7583b861c8 100644
--- a/sys/dev/pci/pci_host_generic.h
+++ b/sys/dev/pci/pci_host_generic.h
@@ -63,6 +63,7 @@ struct pcie_range {
 #define	FLAG_TYPE_IO		0x1
 #define	FLAG_TYPE_MEM		0x2
 #define	FLAG_TYPE_PMEM		0x3
+	struct resource *res;
 };
 
 struct generic_pcie_core_softc {