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
This commit is contained in:
John Baldwin 2024-02-09 10:27:45 -08:00
parent 36efc64a6b
commit b377ff8110

View file

@ -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