Date: Sat, 14 May 2011 21:15:49 +0000 (UTC) From: Marius Strobl <marius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r221925 - stable/8/sys/sparc64/pci Message-ID: <201105142115.p4ELFnNm016347@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marius Date: Sat May 14 21:15:49 2011 New Revision: 221925 URL: http://svn.freebsd.org/changeset/base/221925 Log: MFC: r220039, 220147 - 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 (MFC'ed to stable/8 in r221923) for disabling bus parking for certain EBus bridges in order to work around hardware bugs. - Mark some unused parameters as such. Modified: stable/8/sys/sparc64/pci/psycho.c stable/8/sys/sparc64/pci/psychovar.h Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) Modified: stable/8/sys/sparc64/pci/psycho.c ============================================================================== --- stable/8/sys/sparc64/pci/psycho.c Sat May 14 21:12:00 2011 (r221924) +++ stable/8/sys/sparc64/pci/psycho.c Sat May 14 21:15:49 2011 (r221925) @@ -83,7 +83,8 @@ static void psycho_set_intr(struct psych 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,17 +529,29 @@ psycho_attach(device_t dev) * * For the moment, 32KB should be more than enough. */ - sc->sc_is = malloc(sizeof(struct iommu_state), M_DEVBUF, - M_NOWAIT | M_ZERO); + sc->sc_is = malloc(sizeof(*sc->sc_is), M_DEVBUF, M_NOWAIT | + M_ZERO); if (sc->sc_is == NULL) - panic("%s: malloc iommu_state failed", __func__); + panic("%s: could not malloc IOMMU state", __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 = + malloc(sizeof(*sc->sc_dma_methods), M_DEVBUF, + M_NOWAIT); + if (sc->sc_dma_methods == NULL) + panic("%s: could not malloc DMA methods", + __func__); + memcpy(sc->sc_dma_methods, &iommu_dma_methods, + sizeof(*sc->sc_dma_methods)); + sc->sc_dma_methods->dm_dmamap_sync = + sabre_dmamap_sync; sc->sc_is->is_pmaxaddr = IOMMU_MAXADDR(SABRE_IOMMU_BITS); - else + } else { + sc->sc_dma_methods = &iommu_dma_methods; sc->sc_is->is_pmaxaddr = IOMMU_MAXADDR(PSYCHO_IOMMU_BITS); + } sc->sc_is->is_sb[0] = sc->sc_is->is_sb[1] = 0; if (OF_getproplen(node, "no-streaming-cache") < 0) sc->sc_is->is_sb[0] = sc->sc_pcictl + PCR_STRBUF; @@ -571,6 +559,7 @@ psycho_attach(device_t dev) psycho_iommu_init(sc, 3, dvmabase); } else { /* Just copy IOMMU state, config tag and address. */ + sc->sc_dma_methods = &iommu_dma_methods; sc->sc_is = osc->sc_is; if (OF_getproplen(node, "no-streaming-cache") < 0) sc->sc_is->is_sb[1] = sc->sc_pcictl + PCR_STRBUF; @@ -587,7 +576,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 +1081,20 @@ psycho_read_ivar(device_t dev, device_t 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; + + if ((map->dm_flags & DMF_LOADED) == 0) + return; - (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 ((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 +1140,8 @@ psycho_setup_intr(device_t dev, device_t 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 +1154,10 @@ psycho_setup_intr(device_t dev, device_t 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 +1276,7 @@ psycho_release_resource(device_t bus, de } 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 +1285,7 @@ psycho_get_dma_tag(device_t bus, device_ } 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 +1294,25 @@ psycho_get_node(device_t bus, device_t d 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) { Modified: stable/8/sys/sparc64/pci/psychovar.h ============================================================================== --- stable/8/sys/sparc64/pci/psychovar.h Sat May 14 21:12:00 2011 (r221924) +++ stable/8/sys/sparc64/pci/psychovar.h Sat May 14 21:15:49 2011 (r221925) @@ -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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105142115.p4ELFnNm016347>