Date: Mon, 7 Jan 2013 03:47:59 +0000 (UTC) From: Marcel Moolenaar <marcel@svn.freebsd.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r245122 - in projects/altix2/sys: ia64/include ia64/sgisn kern sys Message-ID: <50ea456f.1f49.19d5564c@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marcel Date: Mon Jan 7 03:47:59 2013 New Revision: 245122 URL: http://svnweb.freebsd.org/changeset/base/245122 Log: o Add a work-around for the race condition between PIO read and DMA. This is implemented by using a new busdma_iommu_sync method that busses can implement. The method is implemented by the SGI PCI HC driver to make sure the DMA has completely landed in memory by triggering an interrupt and waiting for it to arrive in the designated memory location. Any outstanding DMA transactions will have completed if that happens. The work-around is derived from Linux. The upshot of using a new method is that either nexus or root_bus can implement the CPU cache flushing and/or invalidation and in a way suitable for the platform. Thus: the method provides the MI abstraction we need. o Change the existing busdma_iommu_* methods to take the bus device as the first argument. These methods can now access bus softc structures and other "local" information in order to implement xlate, map and unmap. This also applies to the new sync method. o Add a flags field to the mtag structure to hold platform flags. Platform flags are a way for different devices to communicate with each other, as well as provide a means for drivers to handle very platform specific hacks/kluges. The platform-specific flags are saved in the memory descriptor so that they can be used to communicate between different methods as well. Introduce a new platform flag called BUSDMA_MD_IA64_DIRECT32. The flag is used by the SGI SHub and PCI drivers to implement 32-bit direct-mapped DMA. The flag is set in the PCI's xlate method and used by the SHub's xlate and map method, as well as the PCI's map method. o Reimplement busdma_sync() as a wrapper around busdma_sync_range() with address 0 and size ~0. o In _busdma_iommu_xlate() always align and round to the cache line size. Since we're allocating DMA memory, we can and should avoid complications or performance reductions that come from having to maintain coherence -- either in S/W or H/W. Modified: projects/altix2/sys/ia64/include/sgisn.h projects/altix2/sys/ia64/sgisn/sgisn_pcib.c projects/altix2/sys/ia64/sgisn/sgisn_shub.c projects/altix2/sys/kern/busdma_if.m projects/altix2/sys/kern/subr_busdma.c projects/altix2/sys/sys/busdma.h Modified: projects/altix2/sys/ia64/include/sgisn.h ============================================================================== --- projects/altix2/sys/ia64/include/sgisn.h Mon Jan 7 03:36:32 2013 (r245121) +++ projects/altix2/sys/ia64/include/sgisn.h Mon Jan 7 03:47:59 2013 (r245122) @@ -41,6 +41,7 @@ #define SAL_SGISN_IOHUB_INFO 0x02000055 #define SAL_SGISN_IOBUS_INFO 0x02000056 #define SAL_SGISN_IODEV_INFO 0x02000057 +#define SAL_SGISN_IOBUS_FLUSH 0x02000058 #define SAL_SGISN_FEATURE_GET_PROM 0x02000065 #define SAL_SGISN_FEATURE_SET_OS 0x02000066 #define SAL_SGISN_SET_CPUID 0x02000068 @@ -50,7 +51,7 @@ #define SHUB_IVAR_PCIBUS 1 #define SHUB_IVAR_PCISEG 2 -#define SHUB_IVAR_EVENT 3 +#define SHUB_IVAR_NASID 3 #define SHUB_EVENT_CONSOLE 0x100000 @@ -107,7 +108,7 @@ struct sgisn_fwbus { struct sgisn_widget *bus_wgt_info; }; -struct sgisn_fwflush_dev { +struct sgisn_fwflush { uint32_t fld_bus; uint32_t fld_slot; uint32_t fld_pin; @@ -116,25 +117,21 @@ struct sgisn_fwflush_dev { uint64_t start; uint64_t end; } fld_bar[6]; - uint64_t *fld_intr; + uint32_t *fld_intr; uint64_t fld_value; - uint64_t *fld_flush; + uint64_t *fld_addr; uint32_t fld_pci_bus; uint32_t fld_pci_segment; struct sgisn_fwbus *fld_parent; uint64_t fld_xxx; }; -struct sgisn_fwflush_widget { - struct sgisn_fwflush_dev flw_dev[32]; -}; - struct sgisn_fwhub { struct sgisn_geoid hub_geoid; uint16_t hub_nasid; uint16_t hub_peer_nasid; uint32_t _pad; - struct sgisn_fwflush_widget *hub_flush; + struct sgisn_fwflush **hub_flush; uint64_t hub_dma_itte[SGISN_HUB_NITTES]; struct sgisn_widget hub_widget[SGISN_HUB_NWIDGETS]; Modified: projects/altix2/sys/ia64/sgisn/sgisn_pcib.c ============================================================================== --- projects/altix2/sys/ia64/sgisn/sgisn_pcib.c Mon Jan 7 03:36:32 2013 (r245121) +++ projects/altix2/sys/ia64/sgisn/sgisn_pcib.c Mon Jan 7 03:47:59 2013 (r245122) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <vm/pmap.h> #include <machine/bus.h> +#include <machine/cpu.h> #include <machine/pci_cfgreg.h> #include <machine/resource.h> #include <machine/sal.h> @@ -68,6 +69,8 @@ struct sgisn_pcib_softc { u_int sc_busnr; struct rman sc_ioport; struct rman sc_iomem; + uint32_t *sc_flush_intr[PCI_SLOTMAX + 1]; + uint64_t *sc_flush_addr[PCI_SLOTMAX + 1]; }; static int sgisn_pcib_attach(device_t); @@ -99,8 +102,11 @@ static uint32_t sgisn_pcib_cfgread(devic static void sgisn_pcib_cfgwrite(device_t, u_int, u_int, u_int, u_int, uint32_t, int); -static int sgisn_pcib_iommu_xlate(device_t, busdma_mtag_t); -static int sgisn_pcib_iommu_map(device_t, busdma_md_t, u_int, bus_addr_t *); +static int sgisn_pcib_iommu_xlate(device_t, device_t, busdma_mtag_t); +static int sgisn_pcib_iommu_map(device_t, device_t, busdma_md_t, u_int, + bus_addr_t *); +static int sgisn_pcib_iommu_sync(device_t, device_t, busdma_md_t, u_int, + bus_addr_t, bus_size_t); /* * Bus interface definitions. @@ -134,6 +140,7 @@ static device_method_t sgisn_pcib_method /* busdma interface */ DEVMETHOD(busdma_iommu_xlate, sgisn_pcib_iommu_xlate), DEVMETHOD(busdma_iommu_map, sgisn_pcib_iommu_map), + DEVMETHOD(busdma_iommu_sync, sgisn_pcib_iommu_sync), { 0, 0 } }; @@ -414,19 +421,22 @@ sgisn_pcib_rm_init(struct sgisn_pcib_sof static int sgisn_pcib_attach(device_t dev) { + struct ia64_sal_result r; struct sgisn_pcib_softc *sc; + struct sgisn_fwflush *fwflush; device_t parent; - uintptr_t addr, bus, seg; + size_t fwflushsz; + uintptr_t addr, ivar; int error; sc = device_get_softc(dev); sc->sc_dev = dev; parent = device_get_parent(dev); - BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCIBUS, &bus); - sc->sc_busnr = bus; - BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCISEG, &seg); - sc->sc_domain = seg; + BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCIBUS, &ivar); + sc->sc_busnr = ivar; + BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCISEG, &ivar); + sc->sc_domain = ivar; error = sgisn_pcib_rm_init(sc, &sc->sc_ioport, "port"); if (error) @@ -437,7 +447,7 @@ sgisn_pcib_attach(device_t dev) return (error); } - (void)ia64_sal_entry(SAL_SGISN_IOBUS_INFO, seg, bus, + (void)ia64_sal_entry(SAL_SGISN_IOBUS_INFO, sc->sc_domain, sc->sc_busnr, ia64_tpa((uintptr_t)&addr), 0, 0, 0, 0); sc->sc_fwbus = (void *)IA64_PHYS_TO_RR7(addr); sc->sc_ioaddr = IA64_RR_MASK(sc->sc_fwbus->fw_common.bus_base); @@ -446,9 +456,32 @@ sgisn_pcib_attach(device_t dev) &sc->sc_hndl); if (bootverbose) - device_printf(dev, "ASIC=%x, XID=%u\n", + device_printf(dev, "ASIC=%x, XID=%u, TYPE=%u, MODE=%u\n", sc->sc_fwbus->fw_common.bus_asic, - sc->sc_fwbus->fw_common.bus_xid); + sc->sc_fwbus->fw_common.bus_xid, + sc->sc_fwbus->fw_type, sc->sc_fwbus->fw_mode); + + fwflushsz = (PCI_SLOTMAX + 1) * sizeof(struct sgisn_fwflush); + fwflush = contigmalloc(fwflushsz, M_TEMP, M_ZERO, 0UL, ~0UL, 16, 0); + BUS_READ_IVAR(parent, dev, SHUB_IVAR_NASID, &ivar); + r = ia64_sal_entry(SAL_SGISN_IOBUS_FLUSH, ivar, + sc->sc_fwbus->fw_common.bus_xid, ia64_tpa((uintptr_t)fwflush), + 0, 0, 0, 0); + if (r.sal_status == 0) { + int i, slot; + + for (i = 0; i <= PCI_SLOTMAX; i++) { + if (fwflush[i].fld_pci_segment != sc->sc_domain || + fwflush[i].fld_pci_bus != sc->sc_busnr) + continue; + slot = fwflush[i].fld_slot; + sc->sc_flush_intr[slot] = fwflush[i].fld_intr; + sc->sc_flush_addr[slot] = fwflush[i].fld_addr; + device_printf(dev, "slot=%d: flush addr=%p, intr=%p\n", + slot, fwflush[i].fld_addr, fwflush[i].fld_intr); + } + } + contigfree(fwflush, fwflushsz, M_TEMP); device_add_child(dev, "pci", -1); error = bus_generic_attach(dev); @@ -485,17 +518,21 @@ sgisn_pcib_write_ivar(device_t dev, devi } static int -sgisn_pcib_iommu_xlate(device_t dev, busdma_mtag_t mtag) +sgisn_pcib_iommu_xlate(device_t bus, device_t dev, busdma_mtag_t mtag) { + struct sgisn_pcib_softc *sc = device_get_softc(bus); vm_paddr_t bndry = 0x80000000UL; /* * Use a 31-bit direct-mapped window for PCI devices that are not - * 64-bit capable. In that case we also make sure allocations do - * not cross the 2G boundary so that the whole segment can be - * direct mapped. + * 64-bit capable and we're not in PCI-X mode. + * For 31-bit direct-mapped DMA we need to make sure allocations + * do not cross the 2G boundary. */ - if (mtag->dmt_maxaddr < ~0UL) { + if (mtag->dmt_maxaddr < ~0UL && (sc->sc_fwbus->fw_mode & 1) == 0) + mtag->dmt_flags |= BUSDMA_MD_IA64_DIRECT32; + + if (mtag->dmt_flags & BUSDMA_MD_IA64_DIRECT32) { mtag->dmt_maxaddr &= (bndry - 1); if (mtag->dmt_bndry == 0 || mtag->dmt_bndry > bndry) mtag->dmt_bndry = bndry; @@ -504,27 +541,60 @@ sgisn_pcib_iommu_xlate(device_t dev, bus } static int -sgisn_pcib_iommu_map(device_t dev, busdma_md_t md, u_int idx, bus_addr_t *ba_p) +sgisn_pcib_iommu_map(device_t bus, device_t dev, busdma_md_t md, u_int idx, + bus_addr_t *ba_p) { - struct sgisn_pcib_softc *sc = device_get_softc(dev); + struct sgisn_pcib_softc *sc = device_get_softc(bus); busdma_tag_t tag; bus_addr_t maxaddr = 0x80000000UL; bus_addr_t ba; + u_int flags; ba = *ba_p; - if (ba < maxaddr) { - ba |= maxaddr; - *ba_p = ba; + + flags = busdma_md_get_flags(md); + if ((flags & BUSDMA_MD_IA64_DIRECT32) && ba < maxaddr) { + *ba_p = ba | maxaddr; return (0); } tag = busdma_md_get_tag(md); maxaddr = busdma_tag_get_maxaddr(tag); if (maxaddr == ~0UL) { - ba |= ((u_long)sc->sc_fwbus->fw_hub_xid << 60) | (1UL << 59); - *ba_p = ba; + *ba_p = ba | ((u_long)sc->sc_fwbus->fw_hub_xid << 60) | + (1UL << 59); return (0); } + /* XXX 32-bit mapped DMA */ return (ENXIO); } + +static int +sgisn_pcib_iommu_sync(device_t bus, device_t dev, busdma_md_t md, u_int op, + bus_addr_t addr, bus_size_t size) +{ + struct sgisn_pcib_softc *sc = device_get_softc(bus); + volatile uint64_t *fladdr; + volatile uint32_t *flintr; + uintptr_t slot; + int error; + + if ((op & BUSDMA_SYNC_POSTREAD) != BUSDMA_SYNC_POSTREAD) + return (0); + + error = BUS_READ_IVAR(device_get_parent(dev), dev, PCI_IVAR_SLOT, + &slot); + if (error) + return (error); + + fladdr = sc->sc_flush_addr[slot]; + flintr = sc->sc_flush_intr[slot]; + if (fladdr != NULL && flintr != NULL) { + *fladdr = 0; + *flintr = 1; + while (*fladdr != 0x10f) + cpu_spinwait(); + } + return (0); +} Modified: projects/altix2/sys/ia64/sgisn/sgisn_shub.c ============================================================================== --- projects/altix2/sys/ia64/sgisn/sgisn_shub.c Mon Jan 7 03:36:32 2013 (r245121) +++ projects/altix2/sys/ia64/sgisn/sgisn_shub.c Mon Jan 7 03:47:59 2013 (r245122) @@ -91,8 +91,9 @@ static int sgisn_shub_set_resource(devic u_long); static int sgisn_shub_write_ivar(device_t, device_t, int, uintptr_t); -static int sgisn_shub_iommu_xlate(device_t, busdma_mtag_t); -static int sgisn_shub_iommu_map(device_t, busdma_md_t, u_int, bus_addr_t *); +static int sgisn_shub_iommu_xlate(device_t, device_t, busdma_mtag_t); +static int sgisn_shub_iommu_map(device_t, device_t, busdma_md_t, u_int, + bus_addr_t *); /* * Bus interface definitions. @@ -486,16 +487,22 @@ sgisn_shub_attach(device_t dev) static int sgisn_shub_read_ivar(device_t dev, device_t child, int which, uintptr_t *res) { + struct sgisn_shub_softc *sc; uintptr_t ivars; - ivars = (uintptr_t)device_get_ivars(child); switch (which) { case SHUB_IVAR_PCIBUS: + ivars = (uintptr_t)device_get_ivars(child); *res = ivars & 0xff; return (0); case SHUB_IVAR_PCISEG: + ivars = (uintptr_t)device_get_ivars(child); *res = ivars >> 8; return (0); + case SHUB_IVAR_NASID: + sc = device_get_softc(dev); + *res = sc->sc_nasid; + return (0); } return (ENOENT); } @@ -508,16 +515,16 @@ sgisn_shub_write_ivar(device_t dev, devi } static int -sgisn_shub_iommu_xlate(device_t dev, busdma_mtag_t mtag) +sgisn_shub_iommu_xlate(device_t bus, device_t dev, busdma_mtag_t mtag) { struct sgisn_shub_softc *sc; vm_paddr_t maxaddr; - sc = device_get_softc(dev); + sc = device_get_softc(bus); /* - * Always limit the maximum address to the maximum offset within - * this node's cacheable memory space. + * Limit the maximum address to the maximum node offset within an + * address space. */ maxaddr = (1UL << (sc->sc_nasid_shft - 2)) - 1; if (mtag->dmt_maxaddr > maxaddr) @@ -525,7 +532,8 @@ sgisn_shub_iommu_xlate(device_t dev, bus /* * Transpose the address range into the current node's cacheable - * memory space. + * memory space. This makes sure DMA memory is allocated close to + * the device (= within the same node). */ mtag->dmt_minaddr += sc->sc_membase; mtag->dmt_maxaddr += sc->sc_membase; @@ -533,17 +541,34 @@ sgisn_shub_iommu_xlate(device_t dev, bus } static int -sgisn_shub_iommu_map(device_t dev, busdma_md_t md, u_int idx, bus_addr_t *ba_p) +sgisn_shub_iommu_map(device_t bus, device_t dev, busdma_md_t md, u_int idx, + bus_addr_t *ba_p) { struct sgisn_shub_softc *sc; - bus_addr_t ba; + bus_addr_t ba, mask; + u_int flags; - sc = device_get_softc(dev); + sc = device_get_softc(bus); ba = *ba_p; - if (ba >= sc->sc_membase && ba < sc->sc_membase + sc->sc_memsize) { - ba -= sc->sc_membase; - *ba_p = ba; + + /* + * Return the node offset when doing 32-bit direct-mapped DMA. + * The PCI bridge maps this somewhere in the cacheable memory + * of this node. + */ + flags = busdma_md_get_flags(md); + if ((flags & BUSDMA_MD_IA64_DIRECT32) && ba >= sc->sc_membase && + ba < sc->sc_membase + sc->sc_memsize) { + *ba_p = ba - sc->sc_membase; + return (0); } + + /* + * For all other memory addresses, map to a fully qualified bus + * address. + */ + mask = (1UL << (sc->sc_nasid_shft - 2)) - 1; + *ba_p = ((ba >> 2) & ~mask) | (ba & mask); return (0); } Modified: projects/altix2/sys/kern/busdma_if.m ============================================================================== --- projects/altix2/sys/kern/busdma_if.m Mon Jan 7 03:36:32 2013 (r245121) +++ projects/altix2/sys/kern/busdma_if.m Mon Jan 7 03:47:59 2013 (r245122) @@ -34,31 +34,40 @@ INTERFACE busdma; # Default implementations CODE { static int - default_iommu_xlate(device_t dev, busdma_mtag_t mtag) + default_iommu_xlate(device_t bus, device_t dev, busdma_mtag_t mtag) { return (0); } static int - default_iommu_map(device_t dev, busdma_md_t md, u_int idx, - bus_addr_t *ba_p) + default_iommu_map(device_t bus, device_t dev, busdma_md_t md, + u_int idx, bus_addr_t *ba_p) { return (0); } static int - default_iommu_unmap(device_t dev, busdma_md_t md) + default_iommu_unmap(device_t bus, device_t dev, busdma_md_t md) + { + return (0); + } + + static int + default_iommu_sync(device_t bus, device_t dev, busdma_md_t md, + u_int op, bus_addr_t addr, bus_size_t size) { return (0); } }; METHOD int iommu_xlate { + device_t bus; device_t dev; busdma_mtag_t mtag; } DEFAULT default_iommu_xlate; METHOD int iommu_map { + device_t bus; device_t dev; busdma_md_t md; u_int idx; @@ -66,6 +75,17 @@ METHOD int iommu_map { } DEFAULT default_iommu_map; METHOD int iommu_unmap { + device_t bus; device_t dev; busdma_md_t md; } DEFAULT default_iommu_unmap; + +METHOD int iommu_sync { + device_t bus; + device_t dev; + busdma_md_t md; + u_int op; + bus_addr_t addr; + bus_size_t size; +} DEFAULT default_iommu_sync; + Modified: projects/altix2/sys/kern/subr_busdma.c ============================================================================== --- projects/altix2/sys/kern/subr_busdma.c Mon Jan 7 03:36:32 2013 (r245121) +++ projects/altix2/sys/kern/subr_busdma.c Mon Jan 7 03:47:59 2013 (r245122) @@ -166,9 +166,9 @@ _busdma_mtag_dump(const char *func, devi { #ifdef BUSDMA_DEBUG - printf("[%s: %s: min=%#jx, max=%#jx, size=%#jx, align=%#jx, " + printf("[%s: %s: flags=%x, min=%#jx, max=%#jx, size=%#jx, align=%#jx, " "bndry=%#jx]\n", __func__, - (dev != NULL) ? device_get_nameunit(dev) : "*", + (dev != NULL) ? device_get_nameunit(dev) : "*", mtag->dmt_flags, (uintmax_t)mtag->dmt_minaddr, (uintmax_t)mtag->dmt_maxaddr, (uintmax_t)mtag->dmt_maxsz, (uintmax_t)mtag->dmt_align, (uintmax_t)mtag->dmt_bndry); @@ -227,8 +227,9 @@ _busdma_data_dump(const char *func, stru bus_addr_t pa; int sz; - printf("[%s: %s: md=%p {\n", func, - device_get_nameunit(md->md_tag->dt_device), md); + printf("[%s: %s: md=%p, addr=%#jx, size=%#jx {\n", func, + device_get_nameunit(md->md_tag->dt_device), md, + (uintmax_t)addr, (uintmax_t)len); TAILQ_FOREACH(seg, &md->md_seg, mds_chain) { if (seg->mds_busaddr + seg->mds_size <= addr || addr + len <= seg->mds_busaddr) @@ -348,30 +349,38 @@ _busdma_md_create(struct busdma_tag *tag } static int -_busdma_iommu_xlate(device_t leaf, struct busdma_mtag *mtag) +_busdma_iommu_xlate(device_t dev, struct busdma_mtag *mtag) { - device_t dev; + device_t bus; int error; error = 0; - dev = device_get_parent(leaf); - while (!error && dev != root_bus) { - _busdma_mtag_dump(__func__, dev, mtag); - error = BUSDMA_IOMMU_XLATE(dev, mtag); + bus = device_get_parent(dev); + while (!error && bus != root_bus) { + _busdma_mtag_dump(__func__, bus, mtag); + error = BUSDMA_IOMMU_XLATE(bus, dev, mtag); if (!error) - dev = device_get_parent(dev); + bus = device_get_parent(bus); } - _busdma_mtag_dump(__func__, dev, mtag); + + /* + * Always align allocated memory on cache line boundaries and round + * the size up to the next cache line. + */ + mtag->dmt_align = MAX(mtag->dmt_align, CACHE_LINE_SIZE); + mtag->dmt_maxsz = roundup2(mtag->dmt_maxsz, CACHE_LINE_SIZE); + + _busdma_mtag_dump(__func__, bus, mtag); return (error); } static int -_busdma_iommu_map_r(device_t dev, struct busdma_md *md, +_busdma_iommu_map_r(device_t bus, device_t dev, struct busdma_md *md, struct busdma_md_seg *seg) { int error; - if (dev == root_bus) { + if (bus == root_bus) { /* * A bus address and a physical address are one and the same * at this level. @@ -380,35 +389,71 @@ _busdma_iommu_map_r(device_t dev, struct return (0); } - error = _busdma_iommu_map_r(device_get_parent(dev), md, seg); + error = _busdma_iommu_map_r(device_get_parent(bus), dev, md, seg); if (!error) - error = BUSDMA_IOMMU_MAP(dev, md, seg->mds_idx, + error = BUSDMA_IOMMU_MAP(bus, dev, md, seg->mds_idx, &seg->mds_busaddr); return (error); } static int -_busdma_iommu_map(device_t leaf, struct busdma_md *md) +_busdma_iommu_map(device_t dev, struct busdma_md *md) { struct busdma_md_seg *seg; - device_t dev; + device_t bus; int error; _busdma_md_dump(__func__, root_bus, md); - dev = device_get_parent(leaf); + bus = device_get_parent(dev); error = 0; TAILQ_FOREACH(seg, &md->md_seg, mds_chain) { - error = _busdma_iommu_map_r(dev, md, seg); + error = _busdma_iommu_map_r(bus, dev, md, seg); if (error) break; } - if (!error) { - _busdma_md_dump(__func__, leaf, md); - } + if (!error) + _busdma_md_dump(__func__, dev, md); + return (error); +} + +static int +_busdma_iommu_unmap(device_t dev, struct busdma_md *md) +{ + device_t bus; + int error; + + bus = device_get_parent(dev); + error = BUSDMA_IOMMU_UNMAP(bus, dev, md); + if (error) + printf("%s: error=%d\n", __func__, error); + return (error); } static int +_busdma_iommu_sync(device_t dev, struct busdma_md *md, u_int op, + bus_addr_t addr, bus_size_t size) +{ + device_t bus; + int error; + + error = 0; + bus = device_get_parent(dev); + while (!error && bus != root_bus) { + error = BUSDMA_IOMMU_SYNC(bus, dev, md, op, addr, size); + if (!error) + bus = device_get_parent(bus); + } + if (error) + return (error); + + if ((op & BUSDMA_SYNC_PREWRITE) == BUSDMA_SYNC_PREWRITE || + (op & BUSDMA_SYNC_POSTREAD) == BUSDMA_SYNC_POSTREAD) + _busdma_data_dump(__func__, md, addr, size); + return (0); +} + +static int _busdma_md_load(struct busdma_md *md, pmap_t pm, vm_offset_t va, vm_size_t len) { struct busdma_md_seg *seg; @@ -603,6 +648,15 @@ busdma_md_get_busaddr(struct busdma_md * } u_int +busdma_md_get_flags(struct busdma_md *md) +{ + + CTR2(KTR_BUSDMA, "%s: md=%p", __func__, md); + + return ((md != NULL) ? md->md_flags : 0); +} + +u_int busdma_md_get_nsegs(struct busdma_md *md) { @@ -715,7 +769,6 @@ int busdma_md_unload(struct busdma_md *md) { struct busdma_md_seg *seg; - device_t bus; int error; CTR2(KTR_BUSDMA, "%s: md=%p", __func__, md); @@ -728,10 +781,9 @@ busdma_md_unload(struct busdma_md *md) if (md->md_nsegs == 0) return (0); - bus = device_get_parent(md->md_tag->dt_device); - error = BUSDMA_IOMMU_UNMAP(bus, md); + error = _busdma_iommu_unmap(md->md_tag->dt_device, md); if (error) - printf("BUSDMA_IOMMU_UNMAP: error=%d\n", error); + return (error); while ((seg = TAILQ_FIRST(&md->md_seg)) != NULL) { TAILQ_REMOVE(&md->md_seg, seg, mds_chain); @@ -761,6 +813,7 @@ busdma_mem_alloc(struct busdma_tag *tag, if (md == NULL) return (ENOMEM); + mtag.dmt_flags = flags & BUSDMA_MD_PLATFORM_FLAGS; mtag.dmt_minaddr = tag->dt_minaddr; mtag.dmt_maxaddr = tag->dt_maxaddr; mtag.dmt_maxsz = tag->dt_maxsegsz; @@ -773,8 +826,8 @@ busdma_mem_alloc(struct busdma_tag *tag, goto fail; } - mflags = 0; - mflags |= (flags & BUSDMA_ALLOC_ZERO) ? M_ZERO : 0; + md->md_flags |= mtag.dmt_flags & BUSDMA_MD_PLATFORM_FLAGS; + mflags = (flags & BUSDMA_ALLOC_ZERO) ? M_ZERO : 0; idx = 0; maxsz = tag->dt_maxsz; @@ -822,7 +875,6 @@ int busdma_mem_free(struct busdma_md *md) { struct busdma_md_seg *seg; - device_t bus; int error; CTR2(KTR_BUSDMA, "%s: md=%p", __func__, md); @@ -832,10 +884,9 @@ busdma_mem_free(struct busdma_md *md) if ((md->md_flags & BUSDMA_MD_FLAG_ALLOCATED) == 0) return (EINVAL); - bus = device_get_parent(md->md_tag->dt_device); - error = BUSDMA_IOMMU_UNMAP(bus, md); + error = _busdma_iommu_unmap(md->md_tag->dt_device, md); if (error) - printf("BUSDMA_IOMMU_UNMAP: error=%d\n", error); + return (error); while ((seg = TAILQ_FIRST(&md->md_seg)) != NULL) { kmem_free(kernel_map, seg->mds_vaddr, seg->mds_size); @@ -846,26 +897,15 @@ busdma_mem_free(struct busdma_md *md) return (0); } -void -busdma_sync(struct busdma_md *md, u_int op) -{ - - CTR3(KTR_BUSDMA, "%s: md=%p, op=%#x", __func__, md, op); - - if ((op & BUSDMA_SYNC_PREWRITE) == BUSDMA_SYNC_PREWRITE || - (op & BUSDMA_SYNC_POSTREAD) == BUSDMA_SYNC_POSTREAD) - _busdma_data_dump(__func__, md, 0UL, ~0UL); -} - -void +int busdma_sync_range(struct busdma_md *md, u_int op, bus_addr_t addr, - bus_size_t len) + bus_size_t size) { + int error; - CTR5(KTR_BUSDMA, "%s: md=%p, op=%#x, addr=%#jx, len=%#jx", __func__, - md, op, (uintmax_t)addr, (uintmax_t)len); + CTR5(KTR_BUSDMA, "%s: md=%p, op=%#x, addr=%#jx, size=%#jx", __func__, + md, op, (uintmax_t)addr, (uintmax_t)size); - if ((op & BUSDMA_SYNC_PREWRITE) == BUSDMA_SYNC_PREWRITE || - (op & BUSDMA_SYNC_POSTREAD) == BUSDMA_SYNC_POSTREAD) - _busdma_data_dump(__func__, md, addr, len); + error = _busdma_iommu_sync(md->md_tag->dt_device, md, op, addr, size); + return (error); } Modified: projects/altix2/sys/sys/busdma.h ============================================================================== --- projects/altix2/sys/sys/busdma.h Mon Jan 7 03:36:32 2013 (r245121) +++ projects/altix2/sys/sys/busdma.h Mon Jan 7 03:47:59 2013 (r245122) @@ -38,6 +38,7 @@ struct busdma_md; typedef struct busdma_md *busdma_md_t; struct busdma_mtag { + u_int dmt_flags; vm_paddr_t dmt_minaddr; vm_paddr_t dmt_maxaddr; vm_size_t dmt_maxsz; @@ -113,6 +114,7 @@ int busdma_md_load_phys(busdma_md_t md, int busdma_md_load_uio(busdma_md_t md, struct uio *uio, busdma_callback_f cb, void *arg, u_int flags); int busdma_md_unload(busdma_md_t md); +u_int busdma_md_get_flags(busdma_md_t md); u_int busdma_md_get_nsegs(busdma_md_t md); busdma_tag_t busdma_md_get_tag(busdma_md_t md); bus_addr_t busdma_md_get_busaddr(busdma_md_t md, u_int idx); @@ -127,6 +129,16 @@ busdma_md_get_pointer(busdma_md_t md, u_ } /* + * Platform-specific flags kept in the memory descriptor and used + * by the machine-dependent code. They're exposed here to make it + * possible for drivers to use them as well if so needed. + */ +#define BUSDMA_MD_PLATFORM_FLAGS 0xffff + +/* SGI Altix 350 - Map the MD using a 32-bit direct-mapped address. */ +#define BUSDMA_MD_IA64_DIRECT32 0x0001 + +/* * busdma_mem_alloc * returns: errno value * arguments: @@ -136,7 +148,8 @@ busdma_md_get_pointer(busdma_md_t md, u_ */ int busdma_mem_alloc(busdma_tag_t tag, u_int flags, busdma_md_t *md_p); -#define BUSDMA_ALLOC_ZERO 0x10000 +/* Allocate pre-zeroed memory. */ +#define BUSDMA_ALLOC_ZERO 0x10000 /* * busdma_mem_free @@ -148,8 +161,15 @@ int busdma_mem_free(busdma_md_t md); int busdma_start(busdma_md_t md, u_int); int busdma_stop(busdma_md_t md); -void busdma_sync(busdma_md_t md, u_int); -void busdma_sync_range(busdma_md_t md, u_int, vm_paddr_t, vm_size_t); + +int busdma_sync_range(busdma_md_t md, u_int, bus_addr_t, bus_size_t); + +static __inline int +busdma_sync(busdma_md_t md, u_int op) +{ + + return (busdma_sync_range(md, op, 0UL, ~0UL)); +} #define BUSDMA_SYNC_READ 0x10000 #define BUSDMA_SYNC_WRITE 0x20000
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?50ea456f.1f49.19d5564c>