- A closer inspection of the OpenSolaris code indicates that the DMA
syncing for Hummingbird and Sabre bridges should be applied with every BUS_DMASYNC_POSTREAD instead of in a wrapper around interrupt handlers for devices behind PCI-PCI bridges only as suggested by the documentation (code for the latter actually exists in OpenSolaris but is disabled by default), which also makes more sense. - Take advantage of the ofw_pci_setup_device method introduced in r220038 for disabling bus parking for certain EBus bridges in order to - Mark some unused parameters as such.
This commit is contained in:
parent
3584a5f5d1
commit
c71062d2a4
@ -83,7 +83,8 @@ static void psycho_set_intr(struct psycho_softc *, u_int, bus_addr_t,
|
||||
driver_filter_t, driver_intr_t);
|
||||
static int psycho_find_intrmap(struct psycho_softc *, u_int, bus_addr_t *,
|
||||
bus_addr_t *, u_long *);
|
||||
static driver_filter_t psycho_dma_sync_stub;
|
||||
static void sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map,
|
||||
bus_dmasync_op_t op);
|
||||
static void psycho_intr_enable(void *);
|
||||
static void psycho_intr_disable(void *);
|
||||
static void psycho_intr_assign(void *);
|
||||
@ -110,18 +111,17 @@ static device_probe_t psycho_probe;
|
||||
static device_attach_t psycho_attach;
|
||||
static bus_read_ivar_t psycho_read_ivar;
|
||||
static bus_setup_intr_t psycho_setup_intr;
|
||||
static bus_teardown_intr_t psycho_teardown_intr;
|
||||
static bus_alloc_resource_t psycho_alloc_resource;
|
||||
static bus_activate_resource_t psycho_activate_resource;
|
||||
static bus_deactivate_resource_t psycho_deactivate_resource;
|
||||
static bus_release_resource_t psycho_release_resource;
|
||||
static bus_describe_intr_t psycho_describe_intr;
|
||||
static bus_get_dma_tag_t psycho_get_dma_tag;
|
||||
static pcib_maxslots_t psycho_maxslots;
|
||||
static pcib_read_config_t psycho_read_config;
|
||||
static pcib_write_config_t psycho_write_config;
|
||||
static pcib_route_interrupt_t psycho_route_interrupt;
|
||||
static ofw_bus_get_node_t psycho_get_node;
|
||||
static ofw_pci_setup_device_t psycho_setup_device;
|
||||
|
||||
static device_method_t psycho_methods[] = {
|
||||
/* Device interface */
|
||||
@ -135,12 +135,12 @@ static device_method_t psycho_methods[] = {
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
DEVMETHOD(bus_read_ivar, psycho_read_ivar),
|
||||
DEVMETHOD(bus_setup_intr, psycho_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, psycho_teardown_intr),
|
||||
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
|
||||
DEVMETHOD(bus_alloc_resource, psycho_alloc_resource),
|
||||
DEVMETHOD(bus_activate_resource, psycho_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, psycho_deactivate_resource),
|
||||
DEVMETHOD(bus_release_resource, psycho_release_resource),
|
||||
DEVMETHOD(bus_describe_intr, psycho_describe_intr),
|
||||
DEVMETHOD(bus_describe_intr, bus_generic_describe_intr),
|
||||
DEVMETHOD(bus_get_dma_tag, psycho_get_dma_tag),
|
||||
|
||||
/* pcib interface */
|
||||
@ -152,6 +152,9 @@ static device_method_t psycho_methods[] = {
|
||||
/* ofw_bus interface */
|
||||
DEVMETHOD(ofw_bus_get_node, psycho_get_node),
|
||||
|
||||
/* ofw_pci interface */
|
||||
DEVMETHOD(ofw_pci_setup_device, psycho_setup_device),
|
||||
|
||||
KOBJMETHOD_END
|
||||
};
|
||||
|
||||
@ -178,17 +181,6 @@ struct psycho_icarg {
|
||||
bus_addr_t pica_clr;
|
||||
};
|
||||
|
||||
struct psycho_dma_sync {
|
||||
struct psycho_softc *pds_sc;
|
||||
driver_filter_t *pds_handler; /* handler to call */
|
||||
void *pds_arg; /* argument for the handler */
|
||||
void *pds_cookie; /* parent bus int. cookie */
|
||||
device_t pds_ppb; /* farest PCI-PCI bridge */
|
||||
uint8_t pds_bus; /* bus of farest PCI dev. */
|
||||
uint8_t pds_slot; /* slot of farest PCI dev. */
|
||||
uint8_t pds_func; /* func. of farest PCI dev. */
|
||||
};
|
||||
|
||||
#define PSYCHO_READ8(sc, off) \
|
||||
bus_read_8((sc)->sc_mem_res, (off))
|
||||
#define PSYCHO_WRITE8(sc, off, v) \
|
||||
@ -288,16 +280,14 @@ psycho_probe(device_t dev)
|
||||
static int
|
||||
psycho_attach(device_t dev)
|
||||
{
|
||||
char name[sizeof("pci108e,1000")];
|
||||
struct psycho_icarg *pica;
|
||||
struct psycho_softc *asc, *sc, *osc;
|
||||
struct ofw_pci_ranges *range;
|
||||
const struct psycho_desc *desc;
|
||||
bus_addr_t intrclr, intrmap;
|
||||
uint64_t csr, dr;
|
||||
phandle_t child, node;
|
||||
phandle_t node;
|
||||
uint32_t dvmabase, prop, prop_array[2];
|
||||
int32_t rev;
|
||||
u_int rerun, ver;
|
||||
int i, j;
|
||||
|
||||
@ -387,23 +377,9 @@ psycho_attach(device_t dev)
|
||||
|
||||
/* Set up the PCI control and PCI diagnostic registers. */
|
||||
|
||||
/*
|
||||
* Revision 0 EBus bridges have a bug which prevents them from
|
||||
* working when bus parking is enabled.
|
||||
*/
|
||||
rev = -1;
|
||||
csr = PCICTL_READ8(sc, PCR_CS);
|
||||
csr &= ~PCICTL_ARB_PARK;
|
||||
for (child = OF_child(node); child != 0; child = OF_peer(child)) {
|
||||
if (OF_getprop(child, "name", name, sizeof(name)) == -1)
|
||||
continue;
|
||||
if ((strcmp(name, "ebus") == 0 ||
|
||||
strcmp(name, "pci108e,1000") == 0) &&
|
||||
OF_getprop(child, "revision-id", &rev, sizeof(rev)) > 0 &&
|
||||
rev == 0)
|
||||
break;
|
||||
}
|
||||
if (rev != 0 && OF_getproplen(node, "no-bus-parking") < 0)
|
||||
if (OF_getproplen(node, "no-bus-parking") < 0)
|
||||
csr |= PCICTL_ARB_PARK;
|
||||
|
||||
/* Workarounds for version specific bugs. */
|
||||
@ -553,15 +529,19 @@ psycho_attach(device_t dev)
|
||||
*
|
||||
* For the moment, 32KB should be more than enough.
|
||||
*/
|
||||
memcpy(&sc->sc_dma_methods, &iommu_dma_methods,
|
||||
sizeof(sc->sc_dma_methods));
|
||||
sc->sc_is = malloc(sizeof(struct iommu_state), M_DEVBUF,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (sc->sc_is == NULL)
|
||||
panic("%s: malloc iommu_state failed", __func__);
|
||||
sc->sc_is->is_flags = IOMMU_PRESERVE_PROM;
|
||||
if (sc->sc_mode == PSYCHO_MODE_SABRE)
|
||||
if (sc->sc_mode == PSYCHO_MODE_SABRE) {
|
||||
sc->sc_dma_methods.dm_dmamap_sync =
|
||||
sabre_dmamap_sync;
|
||||
sc->sc_is->is_pmaxaddr =
|
||||
IOMMU_MAXADDR(SABRE_IOMMU_BITS);
|
||||
else
|
||||
} else
|
||||
sc->sc_is->is_pmaxaddr =
|
||||
IOMMU_MAXADDR(PSYCHO_IOMMU_BITS);
|
||||
sc->sc_is->is_sb[0] = sc->sc_is->is_sb[1] = 0;
|
||||
@ -587,7 +567,7 @@ psycho_attach(device_t dev)
|
||||
panic("%s: bus_dma_tag_create failed", __func__);
|
||||
/* Customize the tag. */
|
||||
sc->sc_pci_dmat->dt_cookie = sc->sc_is;
|
||||
sc->sc_pci_dmat->dt_mt = &iommu_dma_methods;
|
||||
sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods;
|
||||
|
||||
i = OF_getprop(node, "bus-range", (void *)prop_array,
|
||||
sizeof(prop_array));
|
||||
@ -1092,15 +1072,20 @@ psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_dma_sync_stub(void *arg)
|
||||
static void
|
||||
sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op)
|
||||
{
|
||||
struct psycho_dma_sync *pds = arg;
|
||||
struct iommu_state *is = dt->dt_cookie;
|
||||
|
||||
(void)PCIB_READ_CONFIG(pds->pds_ppb, pds->pds_bus, pds->pds_slot,
|
||||
pds->pds_func, PCIR_VENDOR, 2);
|
||||
(void)PSYCHO_READ8(pds->pds_sc, PSR_DMA_WRITE_SYNC);
|
||||
return (pds->pds_handler(pds->pds_arg));
|
||||
if ((map->dm_flags & DMF_LOADED) == 0)
|
||||
return;
|
||||
|
||||
if ((op & BUS_DMASYNC_POSTREAD) != 0)
|
||||
(void)bus_space_read_8(is->is_bustag, is->is_bushandle,
|
||||
PSR_DMA_WRITE_SYNC);
|
||||
|
||||
if ((op & BUS_DMASYNC_PREWRITE) != 0)
|
||||
membar(Sync);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1146,16 +1131,8 @@ psycho_setup_intr(device_t dev, device_t child, struct resource *ires,
|
||||
int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
|
||||
void **cookiep)
|
||||
{
|
||||
struct {
|
||||
int apb:1;
|
||||
int ppb:1;
|
||||
} found;
|
||||
devclass_t pci_devclass;
|
||||
device_t cdev, pdev, pcidev;
|
||||
struct psycho_softc *sc;
|
||||
struct psycho_dma_sync *pds;
|
||||
u_long vec;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
/*
|
||||
@ -1168,114 +1145,10 @@ psycho_setup_intr(device_t dev, device_t child, struct resource *ires,
|
||||
device_printf(dev, "invalid interrupt vector 0x%lx\n", vec);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Sabre-APB-combination does not automatically flush DMA
|
||||
* write data for devices behind additional PCI-PCI bridges
|
||||
* underneath the APB PCI-PCI bridge. The procedure for a
|
||||
* manual flush is to do a PIO read on the far side of the
|
||||
* farthest PCI-PCI bridge followed by a read of the PCI DMA
|
||||
* write sync register of the Sabre.
|
||||
*/
|
||||
if (sc->sc_mode == PSYCHO_MODE_SABRE) {
|
||||
pds = malloc(sizeof(*pds), M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
if (pds == NULL)
|
||||
return (ENOMEM);
|
||||
pcidev = NULL;
|
||||
found.apb = found.ppb = 0;
|
||||
pci_devclass = devclass_find("pci");
|
||||
for (cdev = child; cdev != dev; cdev = pdev) {
|
||||
pdev = device_get_parent(cdev);
|
||||
if (pcidev == NULL) {
|
||||
if (device_get_devclass(pdev) != pci_devclass)
|
||||
continue;
|
||||
pcidev = cdev;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* NB: APB would also match as PCI-PCI bridges.
|
||||
*/
|
||||
if (pci_get_vendor(cdev) == 0x108e &&
|
||||
pci_get_device(cdev) == 0x5000) {
|
||||
found.apb = 1;
|
||||
break;
|
||||
}
|
||||
if (pci_get_class(cdev) == PCIC_BRIDGE &&
|
||||
pci_get_subclass(cdev) == PCIS_BRIDGE_PCI)
|
||||
found.ppb = 1;
|
||||
}
|
||||
if (found.apb && found.ppb && pcidev != NULL) {
|
||||
pds->pds_sc = sc;
|
||||
pds->pds_arg = arg;
|
||||
pds->pds_ppb =
|
||||
device_get_parent(device_get_parent(pcidev));
|
||||
pds->pds_bus = pci_get_bus(pcidev);
|
||||
pds->pds_slot = pci_get_slot(pcidev);
|
||||
pds->pds_func = pci_get_function(pcidev);
|
||||
if (bootverbose)
|
||||
device_printf(dev, "installed DMA sync "
|
||||
"wrapper for device %d.%d on bus %d\n",
|
||||
pds->pds_slot, pds->pds_func,
|
||||
pds->pds_bus);
|
||||
if (intr == NULL) {
|
||||
pds->pds_handler = filt;
|
||||
error = bus_generic_setup_intr(dev, child,
|
||||
ires, flags, psycho_dma_sync_stub, intr,
|
||||
pds, cookiep);
|
||||
} else {
|
||||
pds->pds_handler = (driver_filter_t *)intr;
|
||||
error = bus_generic_setup_intr(dev, child,
|
||||
ires, flags, filt,
|
||||
(driver_intr_t *)psycho_dma_sync_stub,
|
||||
pds, cookiep);
|
||||
}
|
||||
} else
|
||||
error = bus_generic_setup_intr(dev, child, ires,
|
||||
flags, filt, intr, arg, cookiep);
|
||||
if (error != 0) {
|
||||
free(pds, M_DEVBUF);
|
||||
return (error);
|
||||
}
|
||||
pds->pds_cookie = *cookiep;
|
||||
*cookiep = pds;
|
||||
return (error);
|
||||
}
|
||||
return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr,
|
||||
arg, cookiep));
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_teardown_intr(device_t dev, device_t child, struct resource *vec,
|
||||
void *cookie)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
struct psycho_dma_sync *pds;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
if (sc->sc_mode == PSYCHO_MODE_SABRE) {
|
||||
pds = cookie;
|
||||
error = bus_generic_teardown_intr(dev, child, vec,
|
||||
pds->pds_cookie);
|
||||
if (error == 0)
|
||||
free(pds, M_DEVBUF);
|
||||
return (error);
|
||||
}
|
||||
return (bus_generic_teardown_intr(dev, child, vec, cookie));
|
||||
}
|
||||
|
||||
static int
|
||||
psycho_describe_intr(device_t dev, device_t child, struct resource *vec,
|
||||
void *cookie, const char *descr)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
if (sc->sc_mode == PSYCHO_MODE_SABRE)
|
||||
cookie = ((struct psycho_dma_sync *)cookie)->pds_cookie;
|
||||
return (bus_generic_describe_intr(dev, child, vec, cookie, descr));
|
||||
}
|
||||
|
||||
static struct resource *
|
||||
psycho_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
u_long start, u_long end, u_long count, u_int flags)
|
||||
@ -1394,7 +1267,7 @@ psycho_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
}
|
||||
|
||||
static bus_dma_tag_t
|
||||
psycho_get_dma_tag(device_t bus, device_t child)
|
||||
psycho_get_dma_tag(device_t bus, device_t child __unused)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
|
||||
@ -1403,7 +1276,7 @@ psycho_get_dma_tag(device_t bus, device_t child)
|
||||
}
|
||||
|
||||
static phandle_t
|
||||
psycho_get_node(device_t bus, device_t dev)
|
||||
psycho_get_node(device_t bus, device_t child __unused)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
|
||||
@ -1412,6 +1285,25 @@ psycho_get_node(device_t bus, device_t dev)
|
||||
return (sc->sc_node);
|
||||
}
|
||||
|
||||
static void
|
||||
psycho_setup_device(device_t bus, device_t child)
|
||||
{
|
||||
struct psycho_softc *sc;
|
||||
uint32_t rev;
|
||||
|
||||
sc = device_get_softc(bus);
|
||||
/*
|
||||
* Revision 0 EBus bridges have a bug which prevents them from
|
||||
* working when bus parking is enabled.
|
||||
*/
|
||||
if ((strcmp(ofw_bus_get_name(child), "ebus") == 0 ||
|
||||
strcmp(ofw_bus_get_name(child), "pci108e,1000") == 0) &&
|
||||
OF_getprop(ofw_bus_get_node(child), "revision-id", &rev,
|
||||
sizeof(rev)) > 0 && rev == 0)
|
||||
PCICTL_WRITE8(sc, PCR_CS, PCICTL_READ8(sc, PCR_CS) &
|
||||
~PCICTL_ARB_PARK);
|
||||
}
|
||||
|
||||
static bus_space_tag_t
|
||||
psycho_alloc_bus_tag(struct psycho_softc *sc, int type)
|
||||
{
|
||||
|
@ -36,6 +36,8 @@
|
||||
* per pair of psychos.
|
||||
*/
|
||||
struct psycho_softc {
|
||||
struct bus_dma_methods sc_dma_methods;
|
||||
|
||||
device_t sc_dev;
|
||||
|
||||
struct mtx *sc_mtx;
|
||||
|
Loading…
x
Reference in New Issue
Block a user