mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-21 18:27:22 +00:00
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:
parent
36efc64a6b
commit
b377ff8110
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue