git: b377ff8110e3 - main - pcib: Refine handling of resources allocated from bridge windows

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 09 Feb 2024 18:44:28 UTC
The branch main has been updated by jhb:

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

commit b377ff8110e3489eb6e6b920b51a2384dfc4eb0b
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-02-09 18:27:45 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-02-09 18:27:45 +0000

    pcib: Refine handling of resources allocated from bridge windows
    
    Fix a long-standing layering violation in the original NEW_PCIB code
    by not passing suballocated resources up to the parent bus for
    activation and mapping.  Instead, handle activation and mapping of
    sub-allocated resources in this driver.  When mapping resources,
    request a mapping from a suitable sub-region of the resource allocated
    from the parent bus for the associated bridge window.
    
    Note that this does require passing RF_ACTIVE (with RF_UNMAPPED) when
    allocating bridge window resources from the parent.
    
    Reviewed by:    imp
    Differential Revision:  https://reviews.freebsd.org/D43690
---
 sys/dev/pci/pci_pci.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 126 insertions(+), 4 deletions(-)

diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 5286d4e82e53..02fa8cf1fb9e 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -66,6 +66,10 @@ static bus_alloc_resource_t	pcib_alloc_resource;
 #ifdef NEW_PCIB
 static bus_adjust_resource_t	pcib_adjust_resource;
 static bus_release_resource_t	pcib_release_resource;
+static bus_activate_resource_t	pcib_activate_resource;
+static bus_deactivate_resource_t pcib_deactivate_resource;
+static bus_map_resource_t	pcib_map_resource;
+static bus_unmap_resource_t	pcib_unmap_resource;
 #endif
 static int		pcib_reset_child(device_t dev, device_t child, int flags);
 
@@ -108,12 +112,16 @@ static device_method_t pcib_methods[] = {
 #ifdef NEW_PCIB
     DEVMETHOD(bus_adjust_resource,	pcib_adjust_resource),
     DEVMETHOD(bus_release_resource,	pcib_release_resource),
+    DEVMETHOD(bus_activate_resource,	pcib_activate_resource),
+    DEVMETHOD(bus_deactivate_resource,	pcib_deactivate_resource),
+    DEVMETHOD(bus_map_resource,		pcib_map_resource),
+    DEVMETHOD(bus_unmap_resource,	pcib_unmap_resource),
 #else
     DEVMETHOD(bus_adjust_resource,	bus_generic_adjust_resource),
     DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
-#endif
     DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
+#endif
     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
     DEVMETHOD(bus_reset_child,		pcib_reset_child),
@@ -381,7 +389,7 @@ alloc_ranges(rman_res_t start, rman_res_t end, void *arg)
 		device_printf(as->sc->dev,
 		    "allocating non-ISA range %#jx-%#jx\n", start, end);
 	as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT,
-	    &rid, start, end, end - start + 1, 0);
+	    &rid, start, end, end - start + 1, RF_ACTIVE | RF_UNMAPPED);
 	if (as->res[as->count] == NULL)
 		as->error = ENXIO;
 	else
@@ -454,7 +462,7 @@ pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type,
 	else {
 		rid = w->reg;
 		res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit,
-		    w->limit - w->base + 1, flags);
+		    w->limit - w->base + 1, flags | RF_ACTIVE | RF_UNMAPPED);
 		if (res != NULL)
 			pcib_add_window_resources(w, &res, 1);
 	}
@@ -2001,7 +2009,7 @@ pcib_alloc_new_window(struct pcib_softc *sc, struct pcib_window *w, int type,
 	count = roundup2(count, (rman_res_t)1 << w->step);
 	rid = w->reg;
 	res = bus_alloc_resource(sc->dev, type, &rid, start, end, count,
-	    flags & ~RF_ACTIVE);
+	    flags | RF_ACTIVE | RF_UNMAPPED);
 	if (res == NULL)
 		return (ENOSPC);
 	pcib_add_window_resources(w, &res, 1);
@@ -2452,6 +2460,120 @@ pcib_release_resource(device_t dev, device_t child, int type, int rid,
 	}
 	return (bus_generic_release_resource(dev, child, type, rid, r));
 }
+
+static int
+pcib_activate_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	struct pcib_softc *sc = device_get_softc(dev);
+	struct resource_map map;
+	int error;
+
+	if (!pcib_is_resource_managed(sc, type, r))
+		return (bus_generic_activate_resource(dev, child, type, rid,
+		    r));
+
+	error = rman_activate_resource(r);
+	if (error != 0)
+		return (error);
+
+	if ((rman_get_flags(r) & RF_UNMAPPED) == 0 &&
+	    (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT)) {
+		error = BUS_MAP_RESOURCE(dev, child, type, r, NULL, &map);
+		if (error != 0) {
+			rman_deactivate_resource(r);
+			return (error);
+		}
+
+		rman_set_mapping(r, &map);
+	}
+	return (0);
+}
+
+static int
+pcib_deactivate_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	struct pcib_softc *sc = device_get_softc(dev);
+	struct resource_map map;
+	int error;
+
+	if (!pcib_is_resource_managed(sc, type, r))
+		return (bus_generic_deactivate_resource(dev, child, type, rid,
+		    r));
+
+	error = rman_deactivate_resource(r);
+	if (error != 0)
+		return (error);
+
+	if ((rman_get_flags(r) & RF_UNMAPPED) == 0 &&
+	    (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT)) {
+		rman_get_mapping(r, &map);
+		BUS_UNMAP_RESOURCE(dev, child, type, r, &map);
+	}
+	return (0);
+}
+
+static struct resource *
+pcib_find_parent_resource(struct pcib_window *w, struct resource *r)
+{
+	for (int i = 0; i < w->count; i++) {
+		if (rman_get_start(w->res[i]) <= rman_get_start(r) &&
+		    rman_get_end(w->res[i]) >= rman_get_end(r))
+			return (w->res[i]);
+	}
+	return (NULL);
+}
+
+static int
+pcib_map_resource(device_t dev, device_t child, int type, struct resource *r,
+    struct resource_map_request *argsp, struct resource_map *map)
+{
+	struct pcib_softc *sc = device_get_softc(dev);
+	struct resource_map_request args;
+	struct pcib_window *w;
+	struct resource *pres;
+	rman_res_t length, start;
+	int error;
+
+	w = pcib_get_resource_window(sc, type, r);
+	if (w == NULL)
+		return (bus_generic_map_resource(dev, child, type, r, argsp,
+		    map));
+
+	/* 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);
+
+	pres = pcib_find_parent_resource(w, r);
+	if (pres == NULL)
+		return (ENOENT);
+
+	args.offset = start - rman_get_start(pres);
+	args.length = length;
+	return (bus_generic_map_resource(dev, child, type, pres, &args, map));
+}
+
+static int
+pcib_unmap_resource(device_t dev, device_t child, int type, struct resource *r,
+    struct resource_map *map)
+{
+	struct pcib_softc *sc = device_get_softc(dev);
+	struct pcib_window *w;
+
+	w = pcib_get_resource_window(sc, type, r);
+	if (w != NULL) {
+		r = pcib_find_parent_resource(w, r);
+		if (r == NULL)
+			return (ENOENT);
+	}
+	return (bus_generic_unmap_resource(dev, child, type, r, map));
+}
 #else
 /*
  * We have to trap resource allocation requests and ensure that the bridge