Skip site navigation (1)Skip section navigation (2)
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>