OFWPCI: Improve resource handling.
- add new rman for prefetchable memory. Is used only if given 'ranges' property contains prefetchable memory range. - not all ranges in 'ranges' property are subject for rman's filling. Tegra for example, have two addition records which are used for 'pci 'register' -> 'assigned-address' -> 'ranges' machinery. Add sc_ranges_mask for masking not rman related ranges. - consistently pass unknown (not managed at this level) resources allocation/release/adjust requests to parent. MFC after: 3 weeks
This commit is contained in:
parent
487e2e6507
commit
5572376db2
@ -94,6 +94,7 @@ static phandle_t ofw_pci_get_node(device_t, device_t);
|
||||
* local methods
|
||||
*/
|
||||
static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
|
||||
static struct rman *ofw_pci_get_rman(struct ofw_pci_softc *, int, u_int);
|
||||
|
||||
/*
|
||||
* Driver methods.
|
||||
@ -137,7 +138,7 @@ ofw_pci_init(device_t dev)
|
||||
phandle_t node;
|
||||
u_int32_t busrange[2];
|
||||
struct ofw_pci_range *rp;
|
||||
int error;
|
||||
int i, error;
|
||||
struct ofw_pci_cell_info *cell_info;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
@ -201,17 +202,27 @@ ofw_pci_init(device_t dev)
|
||||
}
|
||||
|
||||
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_mem_rman.rm_descr = "PCI Memory";
|
||||
sc->sc_mem_rman.rm_descr = "PCI Non Prefetchable Memory";
|
||||
error = rman_init(&sc->sc_mem_rman);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "rman_init() failed. error = %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
|
||||
rp->pci_hi != 0; rp++) {
|
||||
error = 0;
|
||||
sc->sc_pmem_rman.rm_type = RMAN_ARRAY;
|
||||
sc->sc_pmem_rman.rm_descr = "PCI Prefetchable Memory";
|
||||
error = rman_init(&sc->sc_pmem_rman);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "rman_init() failed. error = %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->sc_nrange; i++) {
|
||||
error = 0;
|
||||
rp = sc->sc_range + i;
|
||||
|
||||
if (sc->sc_range_mask & ((uint64_t)1 << i))
|
||||
continue;
|
||||
switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
|
||||
case OFW_PCI_PHYS_HI_SPACE_CONFIG:
|
||||
break;
|
||||
@ -221,8 +232,14 @@ ofw_pci_init(device_t dev)
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM32:
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM64:
|
||||
error = rman_manage_region(&sc->sc_mem_rman, rp->pci,
|
||||
rp->pci + rp->size - 1);
|
||||
if (rp->pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) {
|
||||
sc->sc_have_pmem = 1;
|
||||
error = rman_manage_region(&sc->sc_pmem_rman,
|
||||
rp->pci, rp->pci + rp->size - 1);
|
||||
} else {
|
||||
error = rman_manage_region(&sc->sc_mem_rman,
|
||||
rp->pci, rp->pci + rp->size - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -244,6 +261,7 @@ out:
|
||||
free(sc->sc_range, M_DEVBUF);
|
||||
rman_fini(&sc->sc_io_rman);
|
||||
rman_fini(&sc->sc_mem_rman);
|
||||
rman_fini(&sc->sc_pmem_rman);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -385,28 +403,16 @@ ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
struct rman *rm;
|
||||
int needactivate;
|
||||
|
||||
|
||||
needactivate = flags & RF_ACTIVE;
|
||||
flags &= ~RF_ACTIVE;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
switch (type) {
|
||||
case SYS_RES_MEMORY:
|
||||
rm = &sc->sc_mem_rman;
|
||||
break;
|
||||
|
||||
case SYS_RES_IOPORT:
|
||||
rm = &sc->sc_io_rman;
|
||||
break;
|
||||
|
||||
case SYS_RES_IRQ:
|
||||
return (bus_alloc_resource(bus, type, rid, start, end, count,
|
||||
flags));
|
||||
|
||||
default:
|
||||
device_printf(bus, "unknown resource request from %s\n",
|
||||
device_get_nameunit(child));
|
||||
return (NULL);
|
||||
rm = ofw_pci_get_rman(sc, type, flags);
|
||||
if (rm == NULL) {
|
||||
return (bus_generic_alloc_resource(bus, child, type, rid,
|
||||
start, end, count, flags));
|
||||
}
|
||||
|
||||
rv = rman_reserve_resource(rm, start, end, count, flags, child);
|
||||
@ -435,15 +441,24 @@ static int
|
||||
ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
struct rman *rm;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
|
||||
if (rm == NULL) {
|
||||
return (bus_generic_release_resource(bus, child, type, rid,
|
||||
res));
|
||||
}
|
||||
KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
|
||||
|
||||
if (rman_get_flags(res) & RF_ACTIVE) {
|
||||
int error;
|
||||
|
||||
error = bus_deactivate_resource(child, type, rid, res);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (rman_release_resource(res));
|
||||
}
|
||||
|
||||
@ -454,64 +469,63 @@ ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct ofw_pci_softc *sc;
|
||||
bus_space_handle_t handle;
|
||||
bus_space_tag_t tag;
|
||||
struct ofw_pci_range *rp;
|
||||
vm_paddr_t start;
|
||||
int space;
|
||||
int rv;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
if (type == SYS_RES_IRQ) {
|
||||
return (bus_activate_resource(bus, type, rid, res));
|
||||
if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
|
||||
return (bus_generic_activate_resource(bus, child, type, rid,
|
||||
res));
|
||||
}
|
||||
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
|
||||
struct ofw_pci_range *rp;
|
||||
vm_paddr_t start;
|
||||
int space;
|
||||
|
||||
start = (vm_paddr_t)rman_get_start(res);
|
||||
start = (vm_paddr_t)rman_get_start(res);
|
||||
|
||||
/*
|
||||
* Map this through the ranges list
|
||||
*/
|
||||
for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
|
||||
rp->pci_hi != 0; rp++) {
|
||||
if (start < rp->pci || start >= rp->pci + rp->size)
|
||||
continue;
|
||||
/*
|
||||
* Map this through the ranges list
|
||||
*/
|
||||
for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
|
||||
rp->pci_hi != 0; rp++) {
|
||||
if (start < rp->pci || start >= rp->pci + rp->size)
|
||||
continue;
|
||||
|
||||
switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
|
||||
case OFW_PCI_PHYS_HI_SPACE_IO:
|
||||
space = SYS_RES_IOPORT;
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM32:
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM64:
|
||||
space = SYS_RES_MEMORY;
|
||||
break;
|
||||
default:
|
||||
space = -1;
|
||||
switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
|
||||
case OFW_PCI_PHYS_HI_SPACE_IO:
|
||||
space = SYS_RES_IOPORT;
|
||||
break;
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM32:
|
||||
case OFW_PCI_PHYS_HI_SPACE_MEM64:
|
||||
space = SYS_RES_MEMORY;
|
||||
break;
|
||||
default:
|
||||
space = -1;
|
||||
}
|
||||
|
||||
if (type == space) {
|
||||
start += (rp->host - rp->pci);
|
||||
break;
|
||||
}
|
||||
if (type == space) {
|
||||
start += (rp->host - rp->pci);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("ofw_pci mapdev: start %jx, len %jd\n",
|
||||
(rman_res_t)start, rman_get_size(res));
|
||||
|
||||
tag = BUS_GET_BUS_TAG(child, child);
|
||||
if (tag == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
rman_set_bustag(res, tag);
|
||||
rv = bus_space_map(tag, start,
|
||||
rman_get_size(res), 0, &handle);
|
||||
if (rv != 0)
|
||||
return (ENOMEM);
|
||||
|
||||
rman_set_bushandle(res, handle);
|
||||
rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
printf("ofw_pci mapdev: start %jx, len %jd\n",
|
||||
(rman_res_t)start, rman_get_size(res));
|
||||
|
||||
tag = BUS_GET_BUS_TAG(child, child);
|
||||
if (tag == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
rman_set_bustag(res, tag);
|
||||
rv = bus_space_map(tag, start,
|
||||
rman_get_size(res), 0, &handle);
|
||||
if (rv != 0)
|
||||
return (ENOMEM);
|
||||
|
||||
rman_set_bushandle(res, handle);
|
||||
rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */
|
||||
|
||||
return (rman_activate_resource(res));
|
||||
}
|
||||
|
||||
@ -528,17 +542,19 @@ static int
|
||||
ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *res)
|
||||
{
|
||||
struct ofw_pci_softc *sc;
|
||||
vm_size_t psize;
|
||||
|
||||
/*
|
||||
* If this is a memory resource, unmap it.
|
||||
*/
|
||||
if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
|
||||
u_int32_t psize;
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
psize = rman_get_size(res);
|
||||
pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
|
||||
if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
|
||||
return (bus_generic_deactivate_resource(bus, child, type, rid,
|
||||
res));
|
||||
}
|
||||
|
||||
psize = rman_get_size(res);
|
||||
pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
|
||||
|
||||
return (rman_deactivate_resource(res));
|
||||
}
|
||||
|
||||
@ -550,24 +566,15 @@ ofw_pci_adjust_resource(device_t bus, device_t child, int type,
|
||||
struct ofw_pci_softc *sc;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
|
||||
rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
|
||||
if (rm == NULL) {
|
||||
return (bus_generic_adjust_resource(bus, child, type, res,
|
||||
start, end));
|
||||
}
|
||||
KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
|
||||
KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
|
||||
("active resources cannot be adjusted"));
|
||||
if (rman_get_flags(res) & RF_ACTIVE)
|
||||
return (EINVAL);
|
||||
|
||||
switch (type) {
|
||||
case SYS_RES_MEMORY:
|
||||
rm = &sc->sc_mem_rman;
|
||||
break;
|
||||
case SYS_RES_IOPORT:
|
||||
rm = &sc->sc_io_rman;
|
||||
break;
|
||||
default:
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (!rman_is_region_manager(res, rm))
|
||||
return (EINVAL);
|
||||
|
||||
return (rman_adjust_resource(res, start, end));
|
||||
}
|
||||
@ -629,3 +636,22 @@ ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
|
||||
free(base_ranges, M_DEVBUF);
|
||||
return (nranges);
|
||||
}
|
||||
|
||||
static struct rman *
|
||||
ofw_pci_get_rman(struct ofw_pci_softc *sc, int type, u_int flags)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case SYS_RES_IOPORT:
|
||||
return (&sc->sc_io_rman);
|
||||
case SYS_RES_MEMORY:
|
||||
if (sc->sc_have_pmem && (flags & RF_PREFETCHABLE))
|
||||
return (&sc->sc_pmem_rman);
|
||||
else
|
||||
return (&sc->sc_mem_rman);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
@ -60,13 +60,16 @@ struct ofw_pci_softc {
|
||||
int sc_bus;
|
||||
int sc_initialized;
|
||||
int sc_quirks;
|
||||
int sc_have_pmem;
|
||||
|
||||
struct ofw_pci_range *sc_range;
|
||||
int sc_nrange;
|
||||
uint64_t sc_range_mask;
|
||||
struct ofw_pci_cell_info *sc_cell_info;
|
||||
|
||||
struct rman sc_io_rman;
|
||||
struct rman sc_mem_rman;
|
||||
struct rman sc_pmem_rman;
|
||||
bus_space_tag_t sc_memt;
|
||||
bus_dma_tag_t sc_dmat;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user