changeset 7613:e49de7ec7617 onnv_99

PSARC 2008/561 AMD IOMMU 6747701 Integrate DDI hooks for AMD IOMMU 6748625 Intel IOMMU putback broke dom0 boot
author Vikram Hegde <Vikram.Hegde@Sun.COM>
date Mon, 15 Sep 2008 21:50:24 -0700
parents c832bb3d8947
children fca06b3ad595
files usr/src/pkgdefs/SUNWckr/prototype_i386 usr/src/pkgdefs/SUNWhea/prototype_i386 usr/src/uts/common/os/devcfg.c usr/src/uts/common/sys/ddi_impldefs.h usr/src/uts/common/sys/ddi_implfuncs.h usr/src/uts/i86pc/io/rootnex.c usr/src/uts/i86pc/sys/rootnex.h usr/src/uts/intel/Makefile.files usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/io/iommulib.c usr/src/uts/intel/iommulib/Makefile usr/src/uts/intel/sys/Makefile usr/src/uts/intel/sys/iommulib.h
diffstat 13 files changed, 1772 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWckr/prototype_i386	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/pkgdefs/SUNWckr/prototype_i386	Mon Sep 15 21:50:24 2008 -0700
@@ -204,6 +204,7 @@
 f none kernel/misc/hook 755 root sys
 f none kernel/misc/hpcsvc 755 root sys
 f none kernel/misc/idmap 755 root sys
+f none kernel/misc/iommulib 755 root sys
 f none kernel/misc/ipc 755 root sys
 f none kernel/misc/kbtrans 755 root sys
 f none kernel/misc/kcf 755 root sys
@@ -415,6 +416,7 @@
 f none kernel/misc/amd64/hook 755 root sys
 f none kernel/misc/amd64/hpcsvc 755 root sys
 f none kernel/misc/amd64/idmap 755 root sys
+f none kernel/misc/amd64/iommulib 755 root sys
 f none kernel/misc/amd64/ipc 755 root sys
 f none kernel/misc/amd64/kbtrans 755 root sys
 f none kernel/misc/amd64/kcf 755 root sys
--- a/usr/src/pkgdefs/SUNWhea/prototype_i386	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/pkgdefs/SUNWhea/prototype_i386	Mon Sep 15 21:50:24 2008 -0700
@@ -19,10 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 # This required package information file contains a list of package contents.
 # The 'pkgmk' command uses this file to identify the contents of a package
@@ -89,6 +88,7 @@
 f none usr/include/sys/fp.h 644 root bin
 f none usr/include/sys/hypervisor.h 644 root bin
 f none usr/include/sys/i8272A.h 644 root bin
+f none usr/include/sys/iommulib.h 644 root bin
 f none usr/include/sys/kd.h 644 root bin
 f none usr/include/sys/mc.h 644 root bin
 f none usr/include/sys/mc_amd.h 644 root bin
--- a/usr/src/uts/common/os/devcfg.c	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/common/os/devcfg.c	Mon Sep 15 21:50:24 2008 -0700
@@ -3617,6 +3617,39 @@
 }
 
 
+#define	PCI_EX_CLASS	"pciexclass"
+#define	PCI_EX		"pciex"
+#define	PCI_CLASS	"pciclass"
+#define	PCI		"pci"
+
+int
+ddi_is_pci_dip(dev_info_t *dip)
+{
+	char	*prop = NULL;
+
+	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "compatible", &prop) == DDI_PROP_SUCCESS) {
+		ASSERT(prop);
+		if (strncmp(prop, PCI_EX_CLASS, sizeof (PCI_EX_CLASS) - 1)
+		    == 0 ||
+		    strncmp(prop, PCI_EX, sizeof (PCI_EX)- 1)
+		    == 0 ||
+		    strncmp(prop, PCI_CLASS, sizeof (PCI_CLASS) - 1)
+		    == 0 ||
+		    strncmp(prop, PCI, sizeof (PCI) - 1)
+		    == 0) {
+			ddi_prop_free(prop);
+			return (1);
+		}
+	}
+
+	if (prop != NULL) {
+		ddi_prop_free(prop);
+	}
+
+	return (0);
+}
+
 /*
  * Given the pathname of a device, fill in the dev_info_t value and/or the
  * dev_t value and/or the spectype, depending on which parameters are non-NULL.
@@ -3650,9 +3683,9 @@
  * the ioc, look for minor node dhcp. If not found, pass ":dhcp"
  * to ioc's bus_config entry point.
  */
-int
-resolve_pathname(char *pathname,
-	dev_info_t **dipp, dev_t *devtp, int *spectypep)
+static int
+parse_pathname(char *pathname,
+	dev_info_t **dipp, dev_t *devtp, int *spectypep, dev_info_t **pci_dipp)
 {
 	int			error;
 	dev_info_t		*parent, *child;
@@ -3665,6 +3698,9 @@
 	struct ddi_minor_data	*dmn;
 	int			circ;
 
+	if (pci_dipp)
+		*pci_dipp = NULL;
+
 	if (*pathname != '/')
 		return (EINVAL);
 	parent = ddi_root_node();	/* Begin at the top of the tree */
@@ -3707,6 +3743,10 @@
 			pn_free(&pn);
 			kmem_free(component, MAXNAMELEN);
 			kmem_free(config_name, MAXNAMELEN);
+			if (pci_dipp && *pci_dipp) {
+				ndi_rele_devi(*pci_dipp);
+				*pci_dipp = NULL;
+			}
 			return (-1);
 		}
 
@@ -3714,6 +3754,15 @@
 		ndi_rele_devi(parent);
 		parent = child;
 		pn_skipslash(&pn);
+		if (pci_dipp) {
+			if (ddi_is_pci_dip(child)) {
+				ndi_hold_devi(child);
+				if (*pci_dipp != NULL) {
+					ndi_rele_devi(*pci_dipp);
+				}
+				*pci_dipp = child;
+			}
+		}
 	}
 
 	/*
@@ -3731,6 +3780,10 @@
 			kmem_free(config_name, MAXNAMELEN);
 			NDI_CONFIG_DEBUG((CE_NOTE,
 			    "%s: minor node not found\n", pathname));
+			if (pci_dipp && *pci_dipp) {
+				ndi_rele_devi(*pci_dipp);
+				*pci_dipp = NULL;
+			}
 			return (-1);
 		}
 		minorname = NULL;	/* look for default minor */
@@ -3789,7 +3842,7 @@
 	 */
 	if (dipp != NULL)
 		*dipp = parent;
-	else {
+	else if (pci_dipp == NULL) {
 		/*
 		 * We should really keep the ref count to keep the node from
 		 * detaching but ddi_pathname_to_dev_t() specifies a NULL dipp,
@@ -3804,6 +3857,10 @@
 		 * it, and all references, with a call that specifies a dipp.
 		 * In addition, the callers of this new interfaces would then
 		 * need to call ndi_rele_devi when the reference is complete.
+		 *
+		 * NOTE: If pci_dipp is non-NULL we are only interested
+		 * in the PCI parent which is returned held. No need to hold
+		 * the leaf dip.
 		 */
 		(void) ddi_prop_update_int(DDI_DEV_T_NONE, parent,
 		    DDI_NO_AUTODETACH, 1);
@@ -3813,6 +3870,19 @@
 	return (0);
 }
 
+int
+resolve_pathname(char *pathname,
+	dev_info_t **dipp, dev_t *devtp, int *spectypep)
+{
+	return (parse_pathname(pathname, dipp, devtp, spectypep, NULL));
+}
+
+int
+ddi_find_pci_parent(char *pathname, dev_info_t **pci_dipp)
+{
+	return (parse_pathname(pathname, NULL, NULL, NULL, pci_dipp));
+}
+
 /*
  * Given the pathname of a device, return the dev_t of the corresponding
  * device.  Returns NODEV on failure.
--- a/usr/src/uts/common/sys/ddi_impldefs.h	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/common/sys/ddi_impldefs.h	Mon Sep 15 21:50:24 2008 -0700
@@ -88,6 +88,9 @@
 	devi_port_t port_down;
 } devi_bus_priv_t;
 
+struct iommulib_unit;
+typedef struct iommulib_unit *iommulib_handle_t;
+
 struct dev_info  {
 
 	struct dev_info *devi_parent;	/* my parent node in tree	*/
@@ -224,6 +227,9 @@
 
 	/* For intel iommu support */
 	void		*devi_iommu_private;
+
+	/* IOMMU handle */
+	iommulib_handle_t	devi_iommulib_handle;
 };
 
 #define	DEVI(dev_info_type)	((struct dev_info *)(dev_info_type))
--- a/usr/src/uts/common/sys/ddi_implfuncs.h	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/common/sys/ddi_implfuncs.h	Mon Sep 15 21:50:24 2008 -0700
@@ -27,8 +27,6 @@
 #ifndef _SYS_DDI_IMPLFUNCS_H
 #define	_SYS_DDI_IMPLFUNCS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -249,6 +247,8 @@
 int i_ddi_attach_hw_nodes(char *);
 int i_ddi_devs_attached(major_t);
 int i_ddi_minor_node_count(dev_info_t *, const char *);
+int ddi_find_pci_parent(char *pathname, dev_info_t **pci_dipp);
+int ddi_is_pci_dip(dev_info_t *dip);
 
 /* non-DDI functions: wrapper around mod_hold/rele_dev_by_major() */
 struct dev_ops *ddi_hold_driver(major_t);
--- a/usr/src/uts/i86pc/io/rootnex.c	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/i86pc/io/rootnex.c	Mon Sep 15 21:50:24 2008 -0700
@@ -67,14 +67,10 @@
 #include <sys/hypervisor.h>
 #include <sys/bootconf.h>
 #include <vm/kboot_mmu.h>
-#endif
-
+#else
 #include <sys/intel_iommu.h>
-
-/*
- * add to support dmar fault interrupt, will change soon
- */
-char _depends_on[] = "mach/pcplusmp";
+#endif
+
 
 /*
  * enable/disable extra checking of function parameters. Useful for debugging
@@ -157,6 +153,9 @@
 typedef paddr_t rootnex_addr_t;
 #endif
 
+#if !defined(__xpv)
+char _depends_on[] = "mach/pcplusmp misc/iommulib";
+#endif
 
 static struct cb_ops rootnex_cb_ops = {
 	nodev,		/* open */
@@ -211,6 +210,30 @@
 static int rootnex_intr_ops(dev_info_t *pdip, dev_info_t *rdip,
     ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
 
+static int rootnex_coredma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
+    ddi_dma_handle_t *handlep);
+static int rootnex_coredma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle);
+static int rootnex_coredma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+static int rootnex_coredma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle);
+static void rootnex_coredma_reset_cookies(dev_info_t *dip,
+    ddi_dma_handle_t handle);
+static int rootnex_coredma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+static int rootnex_coredma_sync(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags);
+static int rootnex_coredma_win(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+static int rootnex_coredma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep);
+static int rootnex_coredma_mctl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp,
+    size_t *lenp, caddr_t *objpp, uint_t cache_flags);
 
 static struct bus_ops rootnex_bus_ops = {
 	BUSO_REV,
@@ -272,6 +295,21 @@
 	NULL
 };
 
+static iommulib_nexops_t iommulib_nexops = {
+	IOMMU_NEXOPS_VERSION,
+	"Rootnex IOMMU ops Vers 1.1",
+	NULL,
+	rootnex_coredma_allochdl,
+	rootnex_coredma_freehdl,
+	rootnex_coredma_bindhdl,
+	rootnex_coredma_unbindhdl,
+	rootnex_coredma_reset_cookies,
+	rootnex_coredma_get_cookies,
+	rootnex_coredma_sync,
+	rootnex_coredma_win,
+	rootnex_coredma_map,
+	rootnex_coredma_mctl
+};
 
 /*
  *  extern hacks
@@ -434,6 +472,7 @@
 	/* Initialize rootnex event handle */
 	i_ddi_rootnex_init_events(dip);
 
+#if !defined(__xpv)
 #if defined(__amd64)
 	/* probe intel iommu */
 	intel_iommu_probe_and_parse();
@@ -448,6 +487,12 @@
 	}
 #endif
 
+	e = iommulib_nexus_register(dip, &iommulib_nexops,
+	    &rootnex_state->r_iommulib_handle);
+
+	ASSERT(e == DDI_SUCCESS);
+#endif
+
 	return (DDI_SUCCESS);
 }
 
@@ -1543,14 +1588,11 @@
  * ******************
  */
 
-/*
- * rootnex_dma_allochdl()
- *    called from ddi_dma_alloc_handle().
- */
 /*ARGSUSED*/
 static int
-rootnex_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
-    int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
+rootnex_coredma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
+    ddi_dma_handle_t *handlep)
 {
 	uint64_t maxsegmentsize_ll;
 	uint_t maxsegmentsize;
@@ -1687,12 +1729,42 @@
 
 
 /*
- * rootnex_dma_freehdl()
- *    called from ddi_dma_free_handle().
+ * rootnex_dma_allochdl()
+ *    called from ddi_dma_alloc_handle().
  */
+static int
+rootnex_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
+    int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
+{
+#if !defined(__xpv)
+	uint_t error = ENOTSUP;
+	int retval;
+
+	retval = iommulib_nex_open(rdip, &error);
+
+	if (retval != DDI_SUCCESS && error == ENOTSUP) {
+		/* No IOMMU */
+		return (rootnex_coredma_allochdl(dip, rdip, attr, waitfp, arg,
+		    handlep));
+	} else if (retval != DDI_SUCCESS) {
+		return (DDI_FAILURE);
+	}
+
+	ASSERT(IOMMU_USED(rdip));
+
+	/* has an IOMMU */
+	return (iommulib_nexdma_allochdl(dip, rdip, attr,
+	    waitfp, arg, handlep));
+#else
+	return (rootnex_coredma_allochdl(dip, rdip, attr, waitfp, arg,
+	    handlep));
+#endif
+}
+
 /*ARGSUSED*/
 static int
-rootnex_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
+rootnex_coredma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle)
 {
 	ddi_dma_impl_t *hp;
 	rootnex_dma_t *dma;
@@ -1717,15 +1789,27 @@
 	return (DDI_SUCCESS);
 }
 
-
 /*
- * rootnex_dma_bindhdl()
- *    called from ddi_dma_addr_bind_handle() and ddi_dma_buf_bind_handle().
+ * rootnex_dma_freehdl()
+ *    called from ddi_dma_free_handle().
  */
+static int
+rootnex_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_freehdl(dip, rdip, handle));
+	}
+#endif
+	return (rootnex_coredma_freehdl(dip, rdip, handle));
+}
+
+
 /*ARGSUSED*/
 static int
-rootnex_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
-    struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+rootnex_coredma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
 {
 	rootnex_sglinfo_t *sinfo;
 	ddi_dma_attr_t *attr;
@@ -1779,6 +1863,7 @@
 	/* save away the original bind info */
 	dma->dp_dma = dmareq->dmar_object;
 
+#if !defined(__xpv)
 	if (rootnex_state->r_intel_iommu_enabled) {
 		e = intel_iommu_map_sgl(handle, dmareq,
 		    rootnex_state->r_prealloc_cookies);
@@ -1805,6 +1890,7 @@
 			return (DDI_DMA_NORESOURCES);
 		}
 	}
+#endif
 
 rootnex_sgl_start:
 	/*
@@ -1970,19 +2056,33 @@
 
 
 /*
- * rootnex_dma_unbindhdl()
- *    called from ddi_dma_unbind_handle()
+ * rootnex_dma_bindhdl()
+ *    called from ddi_dma_addr_bind_handle() and ddi_dma_buf_bind_handle().
  */
+static int
+rootnex_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_bindhdl(dip, rdip, handle, dmareq,
+		    cookiep, ccountp));
+	}
+#endif
+	return (rootnex_coredma_bindhdl(dip, rdip, handle, dmareq,
+	    cookiep, ccountp));
+}
+
 /*ARGSUSED*/
 static int
-rootnex_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+rootnex_coredma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
     ddi_dma_handle_t handle)
 {
 	ddi_dma_impl_t *hp;
 	rootnex_dma_t *dma;
 	int e;
 
-
 	hp = (ddi_dma_impl_t *)handle;
 	dma = (rootnex_dma_t *)hp->dmai_private;
 
@@ -2020,12 +2120,14 @@
 	rootnex_teardown_copybuf(dma);
 	rootnex_teardown_windows(dma);
 
+#if !defined(__xpv)
 	/*
 	 * If intel iommu enabled, clean up the page tables and free the dvma
 	 */
 	if (rootnex_state->r_intel_iommu_enabled) {
 		intel_iommu_unmap_sgl(handle);
 	}
+#endif
 
 	/*
 	 * If we had to allocate space to for the worse case sgl (it didn't
@@ -2051,6 +2153,56 @@
 	return (DDI_SUCCESS);
 }
 
+/*
+ * rootnex_dma_unbindhdl()
+ *    called from ddi_dma_unbind_handle()
+ */
+/*ARGSUSED*/
+static int
+rootnex_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_unbindhdl(dip, rdip, handle));
+	}
+#endif
+	return (rootnex_coredma_unbindhdl(dip, rdip, handle));
+}
+
+/*ARGSUSED*/
+static void
+rootnex_coredma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle)
+{
+	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
+	rootnex_dma_t *dma = (rootnex_dma_t *)hp->dmai_private;
+
+	hp->dmai_cookie = &dma->dp_cookies[0];
+	hp->dmai_cookie++;
+}
+
+/*ARGSUSED*/
+static int
+rootnex_coredma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
+	rootnex_dma_t *dma = (rootnex_dma_t *)hp->dmai_private;
+
+
+	if (hp->dmai_rflags & DDI_DMA_PARTIAL) {
+		*ccountp = dma->dp_window[dma->dp_current_win].wd_cookie_cnt;
+	} else {
+		*ccountp = dma->dp_sglinfo.si_sgl_size;
+	}
+	*cookiep = dma->dp_cookies[0];
+
+	/* reset the cookies */
+	hp->dmai_cookie = &dma->dp_cookies[0];
+	hp->dmai_cookie++;
+
+	return (DDI_SUCCESS);
+}
 
 /*
  * rootnex_verify_buffer()
@@ -3794,15 +3946,9 @@
 }
 
 
-/*
- * rootnex_dma_sync()
- *    called from ddi_dma_sync() if DMP_NOSYNC is not set in hp->dmai_rflags.
- *    We set DMP_NOSYNC if we're not using the copy buffer. If DMP_NOSYNC
- *    is set, ddi_dma_sync() returns immediately passing back success.
- */
 /*ARGSUSED*/
 static int
-rootnex_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+rootnex_coredma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
     off_t off, size_t len, uint_t cache_flags)
 {
 	rootnex_sglinfo_t *sinfo;
@@ -3935,6 +4081,26 @@
 	return (DDI_SUCCESS);
 }
 
+/*
+ * rootnex_dma_sync()
+ *    called from ddi_dma_sync() if DMP_NOSYNC is not set in hp->dmai_rflags.
+ *    We set DMP_NOSYNC if we're not using the copy buffer. If DMP_NOSYNC
+ *    is set, ddi_dma_sync() returns immediately passing back success.
+ */
+/*ARGSUSED*/
+static int
+rootnex_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+    off_t off, size_t len, uint_t cache_flags)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_sync(dip, rdip, handle, off, len,
+		    cache_flags));
+	}
+#endif
+	return (rootnex_coredma_sync(dip, rdip, handle, off, len,
+	    cache_flags));
+}
 
 /*
  * rootnex_valid_sync_parms()
@@ -3987,13 +4153,9 @@
 }
 
 
-/*
- * rootnex_dma_win()
- *    called from ddi_dma_getwin()
- */
 /*ARGSUSED*/
 static int
-rootnex_dma_win(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+rootnex_coredma_win(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
     uint_t win, off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
     uint_t *ccountp)
 {
@@ -4207,7 +4369,26 @@
 	return (DDI_SUCCESS);
 }
 
-
+/*
+ * rootnex_dma_win()
+ *    called from ddi_dma_getwin()
+ */
+/*ARGSUSED*/
+static int
+rootnex_dma_win(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+    uint_t win, off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
+    uint_t *ccountp)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_win(dip, rdip, handle, win, offp, lenp,
+		    cookiep, ccountp));
+	}
+#endif
+
+	return (rootnex_coredma_win(dip, rdip, handle, win, offp, lenp,
+	    cookiep, ccountp));
+}
 
 /*
  * ************************
@@ -4215,14 +4396,10 @@
  * ************************
  */
 
-/*
- * rootnex_dma_map()
- *    called from ddi_dma_setup()
- */
 /* ARGSUSED */
 static int
-rootnex_dma_map(dev_info_t *dip, dev_info_t *rdip, struct ddi_dma_req *dmareq,
-    ddi_dma_handle_t *handlep)
+rootnex_coredma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep)
 {
 #if defined(__amd64)
 	/*
@@ -4296,6 +4473,22 @@
 #endif /* defined(__amd64) */
 }
 
+/*
+ * rootnex_dma_map()
+ *    called from ddi_dma_setup()
+ */
+/* ARGSUSED */
+static int
+rootnex_dma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_map(dip, rdip, dmareq, handlep));
+	}
+#endif
+	return (rootnex_coredma_map(dip, rdip, dmareq, handlep));
+}
 
 /*
  * rootnex_dma_mctl()
@@ -4303,7 +4496,7 @@
  */
 /* ARGSUSED */
 static int
-rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+rootnex_coredma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
     enum ddi_dma_ctlops request, off_t *offp, size_t *lenp, caddr_t *objpp,
     uint_t cache_flags)
 {
@@ -4488,6 +4681,26 @@
 #endif /* defined(__amd64) */
 }
 
+/*
+ * rootnex_dma_mctl()
+ *
+ */
+/* ARGSUSED */
+static int
+rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
+    enum ddi_dma_ctlops request, off_t *offp, size_t *lenp, caddr_t *objpp,
+    uint_t cache_flags)
+{
+#if !defined(__xpv)
+	if (IOMMU_USED(rdip)) {
+		return (iommulib_nexdma_mctl(dip, rdip, handle, request, offp,
+		    lenp, objpp, cache_flags));
+	}
+#endif
+
+	return (rootnex_coredma_mctl(dip, rdip, handle, request, offp,
+	    lenp, objpp, cache_flags));
+}
 
 /*
  * *********
--- a/usr/src/uts/i86pc/sys/rootnex.h	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/i86pc/sys/rootnex.h	Mon Sep 15 21:50:24 2008 -0700
@@ -34,6 +34,7 @@
 #include <sys/conf.h>
 #include <sys/modctl.h>
 #include <sys/sunddi.h>
+#include <sys/iommulib.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -340,6 +341,7 @@
 	boolean_t		r_reserved_msg_printed;
 	uint64_t		r_counters[ROOTNEX_CNT_LAST];
 	boolean_t		r_intel_iommu_enabled;
+	iommulib_nexhandle_t    r_iommulib_handle;
 } rootnex_state_t;
 
 
--- a/usr/src/uts/intel/Makefile.files	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/intel/Makefile.files	Mon Sep 15 21:50:24 2008 -0700
@@ -252,6 +252,11 @@
 AMR_OBJS = amr.o
 
 #
+#	IOMMULIB module
+#
+IOMMULIB_OBJS = iommulib.o
+
+#
 #	Brand modules
 #
 SN1_BRAND_OBJS	=	sn1_brand.o sn1_brand_asm.o
--- a/usr/src/uts/intel/Makefile.intel.shared	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Mon Sep 15 21:50:24 2008 -0700
@@ -550,6 +550,7 @@
 MISC_KMODS	+= ibmf
 MISC_KMODS	+= ibtl
 MISC_KMODS	+= idmap
+MISC_KMODS	+= iommulib
 MISC_KMODS	+= ipc
 MISC_KMODS	+= kbtrans
 MISC_KMODS	+= kcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/io/iommulib.c	Mon Sep 15 21:50:24 2008 -0700
@@ -0,0 +1,1071 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)iommulib.c	1.6	08/09/07 SMI"
+
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/errno.h>
+#include <sys/modctl.h>
+#include <sys/iommulib.h>
+
+/* ******** Type definitions private to this file  ********************** */
+
+/* 1 per IOMMU unit. There may be more than one per dip */
+typedef struct iommulib_unit {
+	kmutex_t ilu_lock;
+	uint64_t ilu_ref;
+	uint32_t ilu_unitid;
+	dev_info_t *ilu_dip;
+	iommulib_ops_t *ilu_ops;
+	void* ilu_data;
+	struct iommulib_unit *ilu_next;
+	struct iommulib_unit *ilu_prev;
+} iommulib_unit_t;
+
+typedef struct iommulib_cache {
+	dev_info_t *cache_rdip;
+	iommulib_unit_t *cache_unit;
+	struct iommulib_cache *cache_next;
+	struct iommulib_cache *cache_prev;
+} iommulib_cache_t;
+
+typedef struct iommulib_nex {
+	dev_info_t *nex_dip;
+	iommulib_nexops_t nex_ops;
+	struct iommulib_nex *nex_next;
+	struct iommulib_nex *nex_prev;
+} iommulib_nex_t;
+
+/* ********* Function prototypes ********************* */
+static int lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp);
+static void insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp);
+
+
+/* *********  Globals ************************ */
+
+/* IOMMU side: Following data protected by lock */
+static kmutex_t iommulib_lock;
+static iommulib_unit_t   *iommulib_list;
+static uint64_t iommulib_unit_ids = 0;
+static uint64_t iommulib_num_units = 0;
+
+/* rootnex side data */
+
+static kmutex_t iommulib_nexus_lock;
+static iommulib_nex_t *iommulib_nexus_list;
+
+#define	IOMMULIB_CACHE_SIZE 256
+static kmutex_t iommulib_cache_lock;
+static iommulib_cache_t **iommulib_cache;
+
+/* tunable via /etc/system */
+static uint_t iommulib_cache_size = IOMMULIB_CACHE_SIZE;
+
+/* can be set atomically without lock */
+static volatile uint32_t iommulib_fini;
+
+/* debug flag */
+static int iommulib_debug;
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modlmisc modlmisc = {
+	&mod_miscops, "IOMMU library module"
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *)&modlmisc, NULL
+};
+
+int
+_init(void)
+{
+	/*
+	 * static mutexes automagically initialized
+	 * by being allocated in zeroed memory
+	 */
+	mutex_enter(&iommulib_cache_lock);
+	iommulib_cache = kmem_zalloc(
+	    sizeof (iommulib_cache_t *) * iommulib_cache_size, KM_SLEEP);
+	mutex_exit(&iommulib_cache_lock);
+
+	return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+	mutex_enter(&iommulib_lock);
+	if (iommulib_list != NULL || iommulib_nexus_list != NULL) {
+		mutex_exit(&iommulib_lock);
+		return (EBUSY);
+	}
+	iommulib_fini = 1;
+
+	mutex_enter(&iommulib_cache_lock);
+	kmem_free(iommulib_cache,
+	    sizeof (iommulib_cache_t *) * iommulib_cache_size);
+	iommulib_cache = NULL;
+	mutex_exit(&iommulib_cache_lock);
+
+	mutex_exit(&iommulib_lock);
+	return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * Routines with iommulib_iommu_* are invoked from the
+ * IOMMU driver.
+ * Routines with iommulib_nex* are invoked from the
+ * nexus driver (typically rootnex)
+ */
+
+int
+iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops,
+    iommulib_nexhandle_t *handle)
+{
+	iommulib_nex_t *nexp;
+	int instance = ddi_get_instance(dip);
+	const char *driver = ddi_driver_name(dip);
+	dev_info_t *pdip = ddi_get_parent(dip);
+	const char *f = "iommulib_nexus_register";
+
+	ASSERT(nexops);
+	ASSERT(handle);
+
+	*handle = NULL;
+
+	/*
+	 * Root node is never busy held
+	 */
+	if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED ||
+	    !DEVI_BUSY_OWNED(pdip))) {
+		cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED "
+		    "or busy held for nexops vector (%p). Failing registration",
+		    f, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) {
+		cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version "
+		    "in nexops vector (%p). Failing NEXUS registration",
+		    f, driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	ASSERT(nexops->nops_data == NULL);
+
+	if (nexops->nops_id == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL ID field. "
+		    "Failing registration for nexops vector: %p",
+		    f, driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_allochdl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_freehdl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_bindhdl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_sync == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+
+	if (nexops->nops_dma_reset_cookies == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_get_cookies == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_win == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	/* Check for legacy ops */
+	if (nexops->nops_dma_map == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_map op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	if (nexops->nops_dma_mctl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_mctl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)nexops);
+		return (DDI_FAILURE);
+	}
+
+	nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP);
+
+	mutex_enter(&iommulib_lock);
+	if (iommulib_fini == 1) {
+		mutex_exit(&iommulib_lock);
+		cmn_err(CE_WARN, "%s: IOMMULIB unloading. "
+		    "Failing NEXUS register.", f);
+		kmem_free(nexp, sizeof (iommulib_nex_t));
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * fini/register race conditions have been handled. Now create the
+	 * nexus struct
+	 */
+	ndi_hold_devi(dip);
+	nexp->nex_dip = dip;
+	nexp->nex_ops = *nexops;
+
+	mutex_enter(&iommulib_nexus_lock);
+	nexp->nex_next = iommulib_nexus_list;
+	iommulib_nexus_list = nexp;
+	nexp->nex_prev = NULL;
+
+	if (nexp->nex_next != NULL)
+		nexp->nex_next->nex_prev = nexp;
+
+	mutex_exit(&iommulib_nexus_lock);
+	mutex_exit(&iommulib_lock);
+
+	cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s "
+	    "nexops=%p", f, driver, instance, ddi_node_name(dip),
+	    (void *)nexops);
+
+	*handle = nexp;
+
+	return (DDI_SUCCESS);
+}
+
+int
+iommulib_nexus_unregister(iommulib_nexhandle_t handle)
+{
+	dev_info_t *dip;
+	int instance;
+	const char *driver;
+	iommulib_nex_t *nexp = (iommulib_nex_t *)handle;
+	const char *f = "iommulib_nexus_unregister";
+
+	ASSERT(nexp);
+
+	mutex_enter(&iommulib_nexus_lock);
+
+	dip = nexp->nex_dip;
+	driver = ddi_driver_name(dip);
+	instance = ddi_get_instance(dip);
+
+	/* A future enhancement would be to add ref-counts */
+
+	if (nexp->nex_prev == NULL) {
+		iommulib_nexus_list = nexp->nex_next;
+	} else {
+		nexp->nex_prev->nex_next = nexp->nex_next;
+	}
+
+	if (nexp->nex_next != NULL)
+		nexp->nex_next->nex_prev = nexp->nex_prev;
+
+	mutex_exit(&iommulib_nexus_lock);
+
+	kmem_free(nexp, sizeof (iommulib_nex_t));
+
+	cmn_err(CE_WARN, "%s: %s%d: NEXUS (%s) handle successfully "
+	    "unregistered from IOMMULIB", f, driver, instance,
+	    ddi_node_name(dip));
+
+	ndi_rele_devi(dip);
+
+	return (DDI_SUCCESS);
+}
+
+static iommulib_nexops_t *
+lookup_nexops(dev_info_t *dip)
+{
+	iommulib_nex_t  *nexp;
+
+	mutex_enter(&iommulib_nexus_lock);
+	nexp = iommulib_nexus_list;
+	while (nexp) {
+		if (nexp->nex_dip == dip)
+			break;
+		nexp = nexp->nex_next;
+	}
+	mutex_exit(&iommulib_nexus_lock);
+
+	return (nexp ? &nexp->nex_ops : NULL);
+}
+
+int
+iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops,
+    iommulib_handle_t *handle)
+{
+	const char *vendor;
+	iommulib_unit_t *unitp;
+	int instance = ddi_get_instance(dip);
+	const char *driver = ddi_driver_name(dip);
+	dev_info_t *pdip = ddi_get_parent(dip);
+	const char *f = "iommulib_register";
+
+	ASSERT(ops);
+	ASSERT(handle);
+
+	if (i_ddi_node_state(dip) < DS_PROBED || !DEVI_BUSY_OWNED(pdip)) {
+		cmn_err(CE_WARN, "%s: devinfo node not in DS_PROBED or "
+		    "busy held for ops vector (%p). Failing registration",
+		    f, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+
+	if (ops->ilops_vers != IOMMU_OPS_VERSION) {
+		cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version "
+		    "in ops vector (%p). Failing registration", f, driver,
+		    instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	switch (ops->ilops_vendor) {
+	case AMD_IOMMU:
+		vendor = "AMD";
+		break;
+	case INTEL_IOMMU:
+		vendor = "Intel";
+		break;
+	case INVALID_VENDOR:
+		cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, ops->ilops_vendor, (void *)ops);
+		return (DDI_FAILURE);
+	default:
+		cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, ops->ilops_vendor, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	cmn_err(CE_NOTE, "%s: %s%d: Detected IOMMU registration from vendor %s",
+	    f, driver, instance, vendor);
+
+	if (ops->ilops_data == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_id == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL ID field. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_probe == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL probe op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_dma_allochdl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_dma_freehdl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_dma_bindhdl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_dma_sync == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_dma_win == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	/* Check for legacy ops */
+	if (ops->ilops_dma_map == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_map op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	if (ops->ilops_dma_mctl == NULL) {
+		cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_mctl op. "
+		    "Failing registration for ops vector: %p", f,
+		    driver, instance, (void *)ops);
+		return (DDI_FAILURE);
+	}
+
+	unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP);
+	mutex_enter(&iommulib_lock);
+	if (iommulib_fini == 1) {
+		mutex_exit(&iommulib_lock);
+		cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.",
+		    f);
+		kmem_free(unitp, sizeof (iommulib_unit_t));
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * fini/register race conditions have been handled. Now create the
+	 * IOMMU unit
+	 */
+	mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL);
+
+	mutex_enter(&unitp->ilu_lock);
+	unitp->ilu_unitid = ++iommulib_unit_ids;
+	unitp->ilu_ref = 0;
+	ndi_hold_devi(dip);
+	unitp->ilu_dip = dip;
+	unitp->ilu_ops = ops;
+	unitp->ilu_data = ops->ilops_data;
+
+	unitp->ilu_next = iommulib_list;
+	unitp->ilu_prev = NULL;
+	iommulib_list->ilu_prev = unitp;
+	iommulib_list = unitp;
+
+	mutex_exit(&unitp->ilu_lock);
+
+	iommulib_num_units++;
+
+	*handle = unitp;
+
+	mutex_exit(&iommulib_lock);
+
+	cmn_err(CE_NOTE, "%s: %s%d: Succesfully registered IOMMU unit "
+	    "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u",
+	    f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data,
+	    unitp->ilu_unitid);
+
+	return (DDI_SUCCESS);
+}
+
+int
+iommulib_iommu_unregister(iommulib_handle_t handle)
+{
+	uint32_t unitid;
+	dev_info_t *dip;
+	int instance;
+	const char *driver;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+	const char *f = "iommulib_unregister";
+
+	ASSERT(unitp);
+
+	mutex_enter(&iommulib_lock);
+	mutex_enter(&unitp->ilu_lock);
+
+	unitid = unitp->ilu_unitid;
+	dip = unitp->ilu_dip;
+	driver = ddi_driver_name(dip);
+	instance = ddi_get_instance(dip);
+
+	if (unitp->ilu_ref != 0) {
+		mutex_exit(&unitp->ilu_lock);
+		mutex_exit(&iommulib_lock);
+		cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot "
+		    "unregister IOMMULIB unitid %u",
+		    f, driver, instance, unitid);
+		return (DDI_FAILURE);
+	}
+	unitp->ilu_unitid = 0;
+	ASSERT(unitp->ilu_ref == 0);
+
+	if (unitp->ilu_prev == NULL) {
+		iommulib_list = unitp->ilu_next;
+		unitp->ilu_next->ilu_prev = NULL;
+	} else {
+		unitp->ilu_prev->ilu_next = unitp->ilu_next;
+		unitp->ilu_next->ilu_prev = unitp->ilu_prev;
+	}
+
+	iommulib_num_units--;
+
+	mutex_exit(&unitp->ilu_lock);
+
+	mutex_destroy(&unitp->ilu_lock);
+	kmem_free(unitp, sizeof (iommulib_unit_t));
+
+	mutex_exit(&iommulib_lock);
+
+	cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully "
+	    "unregistered", f, driver, instance, unitid);
+
+	ndi_rele_devi(dip);
+
+	return (DDI_SUCCESS);
+}
+
+int
+iommulib_nex_open(dev_info_t *rdip, uint_t *errorp)
+{
+	iommulib_unit_t *unitp;
+	int instance = ddi_get_instance(rdip);
+	const char *driver = ddi_driver_name(rdip);
+	const char *f = "iommulib_nex_open";
+
+	*errorp = 0;
+	DEVI(rdip)->devi_iommulib_handle = NULL;
+
+	/* prevent use of IOMMU for AMD IOMMU's DMA */
+	if (strcmp(driver, "amd_iommu") == 0) {
+		*errorp = ENOTSUP;
+		return (DDI_FAILURE);
+	}
+
+	if (lookup_cache(rdip, &unitp) == DDI_SUCCESS) {
+		DEVI(rdip)->devi_iommulib_handle =
+		    (iommulib_handle_t)unitp;
+		return (DDI_SUCCESS);
+	}
+
+
+	/*
+	 * Ok this dip is not in the cache. Use the probe entry point
+	 * to determine in a hardware specific manner whether this
+	 * dip is controlled by an IOMMU. If yes, insert it into the
+	 * cache and return the handle corresponding to the IOMMU unit.
+	 */
+
+	mutex_enter(&iommulib_lock);
+	for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) {
+		if (unitp->ilu_ops->ilops_probe(rdip) == DDI_SUCCESS)
+			break;
+	}
+
+	if (unitp == NULL) {
+		mutex_exit(&iommulib_lock);
+		if (iommulib_debug) {
+			char buf[MAXPATHLEN];
+			cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not "
+			    "controlled by an IOMMU: path=%s", f, driver,
+			    instance, (void *)rdip, ddi_pathname(rdip, buf));
+		}
+		*errorp = ENOTSUP;
+		return (DDI_FAILURE);
+	}
+
+	mutex_enter(&unitp->ilu_lock);
+	unitp->ilu_ref++;
+	mutex_exit(&unitp->ilu_lock);
+	mutex_exit(&iommulib_lock);
+
+	insert_cache(rdip, unitp);
+
+	DEVI(rdip)->devi_iommulib_handle = unitp;
+
+	return (DDI_SUCCESS);
+}
+
+void
+iommulib_nex_close(dev_info_t *rdip)
+{
+	char buf[MAXPATHLEN];
+	iommulib_unit_t *unitp;
+	const char *driver;
+	int instance;
+	uint32_t unitid;
+	const char *f = "iommulib_nex_close";
+
+	unitp = (iommulib_unit_t *)DEVI(rdip)->devi_iommulib_handle;
+	if (unitp == NULL)
+		return;
+
+	DEVI(rdip)->devi_iommulib_handle = NULL;
+
+	/*
+	 * Assume we don't support DR of IOMMUs. The mapping of
+	 * dips to IOMMU units should not change. Let the mapping
+	 * persist in the cache.
+	 */
+
+	mutex_enter(&iommulib_lock);
+	mutex_enter(&unitp->ilu_lock);
+	unitid = unitp->ilu_unitid;
+	driver = ddi_driver_name(unitp->ilu_dip);
+	instance = ddi_get_instance(unitp->ilu_dip);
+	(void) ddi_pathname(rdip, buf);
+	unitp->ilu_ref--;
+	mutex_exit(&unitp->ilu_lock);
+	mutex_exit(&iommulib_lock);
+
+	if (iommulib_debug) {
+		cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), "
+		    "unitid=%u rdip path = %s", f, driver, instance,
+		    (void *)rdip, unitid, buf);
+	}
+}
+
+int
+iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t),
+    caddr_t arg, ddi_dma_handle_t *dma_handlep)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip,
+	    attr, waitfp, arg, dma_handlep));
+}
+
+int
+iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle)
+{
+	int error;
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip,
+	    rdip, dma_handle);
+
+	iommulib_nex_close(rdip);
+
+	return (error);
+}
+
+int
+iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle,
+	    dmareq, cookiep, ccountp));
+}
+
+int
+iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip,
+	    dma_handle));
+}
+
+int
+iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, off_t off, size_t len,
+    uint_t cache_flags)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle,
+	    off, len, cache_flags));
+}
+
+int
+iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle,
+	    win, offp, lenp, cookiep, ccountp));
+}
+
+/* Obsolete DMA routines */
+
+int
+iommulib_nexdma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *dma_handle)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_map(handle, dip, rdip, dmareq,
+	    dma_handle));
+}
+
+int
+iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, enum ddi_dma_ctlops request,
+    off_t *offp, size_t *lenp, caddr_t *objpp, uint_t cache_flags)
+{
+	iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+	iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	/* No need to grab lock - the handle is reference counted */
+	return (unitp->ilu_ops->ilops_dma_mctl(handle, dip, rdip, dma_handle,
+	    request, offp, lenp, objpp, cache_flags));
+}
+
+/* Utility routines invoked by IOMMU drivers */
+int
+iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
+    ddi_dma_handle_t *handlep)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg,
+	    handlep));
+}
+
+int
+iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_freehdl(dip, rdip, handle));
+}
+
+int
+iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq,
+	    cookiep, ccountp));
+}
+
+int
+iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_unbindhdl(dip, rdip, handle));
+}
+
+void
+iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	nexops->nops_dma_reset_cookies(dip, handle);
+}
+
+int
+iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_get_cookies(dip, handle, cookiep, ccountp));
+}
+
+int
+iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_sync(dip, rdip, handle, off, len,
+	    cache_flags));
+}
+
+int
+iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp,
+	    cookiep, ccountp));
+}
+
+int
+iommulib_iommu_dma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_map(dip, rdip, dmareq, handlep));
+}
+
+int
+iommulib_iommu_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp,
+    size_t *lenp, caddr_t *objpp, uint_t cache_flags)
+{
+	iommulib_nexops_t *nexops = lookup_nexops(dip);
+	if (nexops == NULL)
+		return (DDI_FAILURE);
+	return (nexops->nops_dma_mctl(dip, rdip, handle, request, offp, lenp,
+	    objpp, cache_flags));
+}
+
+int
+iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp)
+{
+	iommulib_unit_t *unitp;
+	uint64_t unitid;
+
+	unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+	ASSERT(unitidp);
+
+	mutex_enter(&unitp->ilu_lock);
+	unitid = unitp->ilu_unitid;
+	mutex_exit(&unitp->ilu_lock);
+
+	ASSERT(unitid > 0);
+	*unitidp = (uint64_t)unitid;
+
+	return (DDI_SUCCESS);
+}
+
+dev_info_t *
+iommulib_iommu_getdip(iommulib_handle_t handle)
+{
+	iommulib_unit_t *unitp;
+	dev_info_t *dip;
+
+	unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	mutex_enter(&unitp->ilu_lock);
+	dip = unitp->ilu_dip;
+	ASSERT(dip);
+	ndi_hold_devi(dip);
+	mutex_exit(&unitp->ilu_lock);
+
+	return (dip);
+}
+
+iommulib_ops_t *
+iommulib_iommu_getops(iommulib_handle_t handle)
+{
+	iommulib_unit_t *unitp;
+	iommulib_ops_t *ops;
+
+	unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	mutex_enter(&unitp->ilu_lock);
+	ops = unitp->ilu_ops;
+	mutex_exit(&unitp->ilu_lock);
+
+	ASSERT(ops);
+
+	return (ops);
+}
+
+void *
+iommulib_iommu_getdata(iommulib_handle_t handle)
+{
+	iommulib_unit_t *unitp;
+	void *data;
+
+	unitp = (iommulib_unit_t *)handle;
+
+	ASSERT(unitp);
+
+	mutex_enter(&unitp->ilu_lock);
+	data = unitp->ilu_data;
+	mutex_exit(&unitp->ilu_lock);
+
+	ASSERT(data);
+
+	return (data);
+}
+
+/*
+ * Internal routines
+ */
+
+static uint32_t
+hashfn(uint64_t ptr)
+{
+	return (ptr % iommulib_cache_size);
+}
+
+static int
+lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp)
+{
+	uint64_t idx;
+	iommulib_cache_t *cachep;
+	iommulib_unit_t *unitp;
+	int retval = DDI_FAILURE;
+
+	*unitpp = NULL;
+
+	mutex_enter(&iommulib_lock);
+	mutex_enter(&iommulib_cache_lock);
+
+	ASSERT(iommulib_cache);
+
+	idx = hashfn((uint64_t)(uintptr_t)rdip);
+
+	ASSERT(idx < iommulib_cache_size);
+
+	for (cachep = iommulib_cache[idx]; cachep;
+	    cachep = cachep->cache_next) {
+		if (cachep->cache_rdip == rdip)
+			break;
+	}
+
+	if (cachep != NULL) {
+		unitp = cachep->cache_unit;
+		mutex_enter(&unitp->ilu_lock);
+		unitp->ilu_ref++;
+		mutex_exit(&unitp->ilu_lock);
+		*unitpp = unitp;
+		retval = DDI_SUCCESS;
+	}
+
+	mutex_exit(&iommulib_cache_lock);
+	mutex_exit(&iommulib_lock);
+	return (retval);
+}
+
+static void
+insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp)
+{
+	uint32_t idx;
+	iommulib_cache_t *cachep;
+
+	mutex_enter(&iommulib_lock);
+	mutex_enter(&iommulib_cache_lock);
+
+	ASSERT(iommulib_cache);
+
+	idx = hashfn((uint64_t)(uintptr_t)rdip);
+
+	ASSERT(idx < iommulib_cache_size);
+
+	for (cachep = iommulib_cache[idx]; cachep;
+	    cachep = cachep->cache_next) {
+		if (cachep->cache_rdip == rdip)
+			break;
+	}
+
+	if (cachep == NULL) {
+		cachep = kmem_zalloc(sizeof (iommulib_cache_t), KM_SLEEP);
+		cachep->cache_rdip = rdip;
+		cachep->cache_unit = unitp;	/* ref-count set by caller */
+		cachep->cache_prev = NULL;
+		cachep->cache_next = iommulib_cache[idx];
+		if (cachep->cache_next)
+			cachep->cache_next->cache_prev = cachep;
+		iommulib_cache[idx] = cachep;
+	}
+
+	mutex_exit(&iommulib_cache_lock);
+	mutex_exit(&iommulib_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/iommulib/Makefile	Mon Sep 15 21:50:24 2008 -0700
@@ -0,0 +1,98 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"@(#)Makefile	1.8	07/01/10 SMI"
+#
+#	This makefile drives the production of the IOMMULIB misc
+#	kernel module.
+#
+#	intel architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE		= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= iommulib
+OBJECTS		= $(IOMMULIB_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(IOMMULIB_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
+INC_PATH        += -I$(UTSBASE)/intel
+INC_PATH	+= -I$(UTSBASE)/i86pc
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(CONFMOD)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Overrides.
+#
+DEBUG_DEFS	+= $(DEBUG_FLGS)
+
+#
+# lint pass one non-enforcement
+#
+CFLAGS += $(CCVERBOSE)
+
+#
+# 3rd party code is not lint clean
+#
+LINTFLAGS += -errwarn=%all
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/intel/sys/Makefile	Mon Sep 15 22:45:56 2008 -0700
+++ b/usr/src/uts/intel/sys/Makefile	Mon Sep 15 21:50:24 2008 -0700
@@ -22,7 +22,6 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 #
 
 include ../../../Makefile.master
@@ -47,6 +46,7 @@
 	fp.h			\
 	frame.h			\
 	inline.h		\
+	iommulib.h		\
 	hypervisor.h		\
 	kd.h			\
 	kdi_machimpl.h		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/sys/iommulib.h	Mon Sep 15 21:50:24 2008 -0700
@@ -0,0 +1,250 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_IOMMULIB_H
+#define	_SYS_IOMMULIB_H
+
+#pragma ident	"@(#)iommulib.h	1.3	08/08/31 SMI"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/ddi_impldefs.h>
+
+#ifdef	_KERNEL
+
+typedef enum {
+	INVALID_VENDOR = 0,
+	AMD_IOMMU,
+	INTEL_IOMMU
+} iommulib_vendor_t;
+
+typedef enum {
+	IOMMU_OPS_VERSION_INVALID = 0,
+	IOMMU_OPS_VERSION_1 = 1
+} iommulib_opsversion_t;
+
+#define	IOMMU_OPS_VERSION IOMMU_OPS_VERSION_1
+
+typedef struct iommulib_ops {
+	iommulib_opsversion_t	ilops_vers;
+	iommulib_vendor_t	ilops_vendor;
+	char			*ilops_id;
+	void			*ilops_data;
+
+	int	(*ilops_probe)(dev_info_t *rdip);
+
+	int	(*ilops_dma_allochdl)(iommulib_handle_t handle,
+	    dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
+	    int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep);
+
+	int	(*ilops_dma_freehdl)(iommulib_handle_t handle,
+	    dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
+
+	int	(*ilops_dma_bindhdl)(iommulib_handle_t handle, dev_info_t *dip,
+	    dev_info_t *rdip, ddi_dma_handle_t dma_handle,
+	    struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep,
+	    uint_t *ccountp);
+
+	int	(*ilops_dma_unbindhdl)(iommulib_handle_t handle,
+	    dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
+
+	int	(*ilops_dma_sync)(iommulib_handle_t handle, dev_info_t *dip,
+	    dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off,
+	    size_t len, uint_t cache_flags);
+
+	int	(*ilops_dma_win)(iommulib_handle_t handle, dev_info_t *dip,
+	    dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
+	    off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
+	    uint_t *ccountp);
+
+
+	/* Obsolete DMA routines */
+
+	int	(*ilops_dma_map)(iommulib_handle_t handle, dev_info_t *dip,
+	    dev_info_t *rdip, struct ddi_dma_req *dmareq,
+	    ddi_dma_handle_t *dma_handle);
+
+	int	(*ilops_dma_mctl)(iommulib_handle_t handle, dev_info_t *dip,
+	    dev_info_t *rdip, ddi_dma_handle_t dma_handle,
+	    enum ddi_dma_ctlops request, off_t *offp, size_t *lenp,
+	    caddr_t *objpp, uint_t cache_flags);
+
+} iommulib_ops_t;
+
+#define	IOMMU_USED(dip)	(DEVI(dip)->devi_iommulib_handle != NULL)
+
+typedef enum {
+	IOMMU_NEXOPS_VERSION_INVALID = 0,
+	IOMMU_NEXOPS_VERSION_1 = 1
+} iommulib_nexops_version_t;
+
+#define	IOMMU_NEXOPS_VERSION IOMMU_NEXOPS_VERSION_1
+
+typedef struct iommulib_nexops {
+	iommulib_nexops_version_t	nops_vers;
+	char			*nops_id;
+	void			*nops_data;
+
+	int (*nops_dma_allochdl)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
+	    ddi_dma_handle_t *handlep);
+
+	int (*nops_dma_freehdl)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_handle_t handle);
+
+	int (*nops_dma_bindhdl)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+	    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+	int (*nops_dma_unbindhdl)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_handle_t handle);
+
+	void (*nops_dma_reset_cookies)(dev_info_t *dip,
+	    ddi_dma_handle_t handle);
+
+	int (*nops_dma_get_cookies)(dev_info_t *dip, ddi_dma_handle_t handle,
+	    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+	int (*nops_dma_sync)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags);
+
+	int (*nops_dma_win)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp,
+	    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+	int (*nops_dma_map)(dev_info_t *dip, dev_info_t *rdip,
+	    struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep);
+
+	int (*nops_dma_mctl)(dev_info_t *dip, dev_info_t *rdip,
+	    ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp,
+	    size_t *lenp, caddr_t *objpp, uint_t cache_flags);
+} iommulib_nexops_t;
+
+struct iommulib_nex;
+typedef struct iommulib_nex *iommulib_nexhandle_t;
+
+/*
+ * Interfaces for nexus drivers - typically rootnex
+ */
+
+int iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops,
+    iommulib_nexhandle_t *handle);
+
+int iommulib_nexus_unregister(iommulib_nexhandle_t handle);
+
+int iommulib_nex_open(dev_info_t *rdip, uint_t *errorp);
+void iommulib_nex_close(dev_info_t *rdip);
+
+int iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t),
+    caddr_t arg, ddi_dma_handle_t *dma_handlep);
+
+int iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle);
+
+int iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+int iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle);
+
+int iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, off_t off, size_t len,
+    uint_t cache_flags);
+
+int iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+int iommulib_nexdma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *dma_handle);
+
+int iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t dma_handle, enum ddi_dma_ctlops request,
+    off_t *offp, size_t *lenp, caddr_t *objpp, uint_t cache_flags);
+
+/*
+ * Interfaces for IOMMU drivers provided by IOMMULIB
+ */
+
+int iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops,
+    iommulib_handle_t *handle);
+
+int iommulib_iommu_unregister(iommulib_handle_t handle);
+
+int iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp);
+
+dev_info_t *iommulib_iommu_getdip(iommulib_handle_t handle);
+
+iommulib_ops_t *iommulib_iommu_getops(iommulib_handle_t handle);
+
+void *iommulib_iommu_getdata(iommulib_handle_t handle);
+
+
+/* Interfaces for IOMMU drivers provided by NEXUS drivers (typically rootnex) */
+
+int iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg,
+    ddi_dma_handle_t *handlep);
+
+int iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle);
+
+int iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+int iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle);
+
+void iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle);
+
+int iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+int iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags);
+
+int iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp,
+    ddi_dma_cookie_t *cookiep, uint_t *ccountp);
+
+int iommulib_iommu_dma_map(dev_info_t *dip, dev_info_t *rdip,
+    struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep);
+
+int iommulib_iommu_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
+    ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp,
+    size_t *lenp, caddr_t *objpp, uint_t cache_flags);
+
+#endif	/* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_IOMMULIB_H */