summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel/io/iommulib.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/intel/io/iommulib.c')
-rw-r--r--usr/src/uts/intel/io/iommulib.c216
1 files changed, 136 insertions, 80 deletions
diff --git a/usr/src/uts/intel/io/iommulib.c b/usr/src/uts/intel/io/iommulib.c
index 173e03de0d..8f36f92894 100644
--- a/usr/src/uts/intel/io/iommulib.c
+++ b/usr/src/uts/intel/io/iommulib.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#pragma ident "@(#)iommulib.c 1.6 08/09/07 SMI"
@@ -43,6 +42,7 @@ typedef struct iommulib_unit {
void* ilu_data;
struct iommulib_unit *ilu_next;
struct iommulib_unit *ilu_prev;
+ iommulib_nexhandle_t ilu_nex;
} iommulib_unit_t;
typedef struct iommulib_nex {
@@ -50,6 +50,7 @@ typedef struct iommulib_nex {
iommulib_nexops_t nex_ops;
struct iommulib_nex *nex_next;
struct iommulib_nex *nex_prev;
+ uint_t nex_ref;
} iommulib_nex_t;
/* ********* Globals ************************ */
@@ -230,6 +231,20 @@ iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops,
return (DDI_FAILURE);
}
+ if (nexops->nops_dmahdl_setprivate == NULL) {
+ cmn_err(CE_WARN, "%s: %s%d: NULL nops_dmahdl_setprivate op. "
+ "Failing registration for ops vector: %p", f,
+ driver, instance, (void *)nexops);
+ return (DDI_FAILURE);
+ }
+
+ if (nexops->nops_dmahdl_getprivate == NULL) {
+ cmn_err(CE_WARN, "%s: %s%d: NULL nops_dmahdl_getprivate 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. "
@@ -272,6 +287,15 @@ iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops,
if (nexp->nex_next != NULL)
nexp->nex_next->nex_prev = nexp;
+ nexp->nex_ref = 0;
+
+ /*
+ * The nexus device won't be controlled by an IOMMU.
+ */
+ DEVI(dip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED;
+
+ DEVI(dip)->devi_iommulib_nex_handle = nexp;
+
mutex_exit(&iommulib_nexus_lock);
mutex_exit(&iommulib_lock);
@@ -295,6 +319,9 @@ iommulib_nexus_unregister(iommulib_nexhandle_t handle)
ASSERT(nexp);
+ if (nexp->nex_ref != 0)
+ return (DDI_FAILURE);
+
mutex_enter(&iommulib_nexus_lock);
dip = nexp->nex_dip;
@@ -325,23 +352,6 @@ iommulib_nexus_unregister(iommulib_nexhandle_t handle)
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)
@@ -350,20 +360,11 @@ iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops,
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,
@@ -494,6 +495,11 @@ iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops,
if (unitp->ilu_next)
unitp->ilu_next->ilu_prev = unitp;
+ /*
+ * The IOMMU device itself is not controlled by an IOMMU.
+ */
+ DEVI(dip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED;
+
mutex_exit(&unitp->ilu_lock);
iommulib_num_units++;
@@ -567,24 +573,20 @@ iommulib_iommu_unregister(iommulib_handle_t handle)
}
int
-iommulib_nex_open(dev_info_t *rdip, uint_t *errorp)
+iommulib_nex_open(dev_info_t *dip, dev_info_t *rdip)
{
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;
-
- if (IOMMU_USED(rdip))
- return (DDI_SUCCESS);
-
+ ASSERT(DEVI(dip)->devi_iommulib_nex_handle != NULL);
ASSERT(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);
+ DEVI(rdip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED;
+ return (DDI_ENOTSUP);
}
/*
@@ -608,16 +610,18 @@ iommulib_nex_open(dev_info_t *rdip, uint_t *errorp)
instance, (void *)rdip, ddi_pathname(rdip, buf));
kmem_free(buf, MAXPATHLEN);
}
- *errorp = ENOTSUP;
- return (DDI_FAILURE);
+ DEVI(rdip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED;
+ return (DDI_ENOTSUP);
}
mutex_enter(&unitp->ilu_lock);
+ unitp->ilu_nex = DEVI(dip)->devi_iommulib_nex_handle;
unitp->ilu_ref++;
+ DEVI(rdip)->devi_iommulib_handle = unitp;
mutex_exit(&unitp->ilu_lock);
mutex_exit(&iommulib_lock);
- DEVI(rdip)->devi_iommulib_handle = unitp;
+ atomic_inc_uint(&DEVI(dip)->devi_iommulib_nex_handle->nex_ref);
return (DDI_SUCCESS);
}
@@ -629,23 +633,29 @@ iommulib_nex_close(dev_info_t *rdip)
const char *driver;
int instance;
uint32_t unitid;
+ iommulib_nex_t *nexp;
const char *f = "iommulib_nex_close";
- unitp = (iommulib_unit_t *)DEVI(rdip)->devi_iommulib_handle;
- if (unitp == NULL)
- return;
+ ASSERT(IOMMU_USED(rdip));
- DEVI(rdip)->devi_iommulib_handle = NULL;
+ unitp = DEVI(rdip)->devi_iommulib_handle;
mutex_enter(&iommulib_lock);
mutex_enter(&unitp->ilu_lock);
+
+ nexp = (iommulib_nex_t *)unitp->ilu_nex;
+ DEVI(rdip)->devi_iommulib_handle = NULL;
+
unitid = unitp->ilu_unitid;
driver = ddi_driver_name(unitp->ilu_dip);
instance = ddi_get_instance(unitp->ilu_dip);
+
unitp->ilu_ref--;
mutex_exit(&unitp->ilu_lock);
mutex_exit(&iommulib_lock);
+ atomic_dec_uint(&nexp->nex_ref);
+
if (iommulib_debug) {
char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
(void) ddi_pathname(rdip, buf);
@@ -778,15 +788,38 @@ iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip,
request, offp, lenp, objpp, cache_flags));
}
+int
+iommulib_nexdma_mapobject(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq,
+ ddi_dma_obj_t *dmao)
+{
+ iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+ iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+ return (unitp->ilu_ops->ilops_dma_mapobject(handle, dip, rdip,
+ dma_handle, dmareq, dmao));
+}
+
+int
+iommulib_nexdma_unmapobject(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao)
+{
+ iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle;
+ iommulib_unit_t *unitp = (iommulib_unit_t *)handle;
+
+ return (unitp->ilu_ops->ilops_dma_unmapobject(handle, dip, rdip,
+ dma_handle, dmao));
+}
+
/* 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg,
handlep));
}
@@ -795,9 +828,10 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
+ ASSERT(nexops);
return (nexops->nops_dma_freehdl(dip, rdip, handle));
}
@@ -806,9 +840,9 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq,
cookiep, ccountp));
}
@@ -817,16 +851,18 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
nexops->nops_dma_reset_cookies(dip, handle);
}
@@ -834,9 +870,9 @@ int
iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle,
ddi_dma_cookie_t **cookiepp, uint_t *ccountp)
{
- iommulib_nexops_t *nexops = lookup_nexops(dip);
- if (nexops == NULL)
- return (DDI_FAILURE);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_get_cookies(dip, handle, cookiepp, ccountp));
}
@@ -844,27 +880,27 @@ int
iommulib_iommu_dma_set_cookies(dev_info_t *dip, ddi_dma_handle_t handle,
ddi_dma_cookie_t *cookiep, uint_t ccount)
{
- iommulib_nexops_t *nexops = lookup_nexops(dip);
- if (nexops == NULL)
- return (DDI_FAILURE);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_set_cookies(dip, handle, cookiep, ccount));
}
int
iommulib_iommu_dma_clear_cookies(dev_info_t *dip, ddi_dma_handle_t handle)
{
- iommulib_nexops_t *nexops = lookup_nexops(dip);
- if (nexops == NULL)
- return (DDI_FAILURE);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_clear_cookies(dip, handle));
}
int
iommulib_iommu_dma_get_sleep_flags(dev_info_t *dip, ddi_dma_handle_t handle)
{
- iommulib_nexops_t *nexops = lookup_nexops(dip);
- if (nexops == NULL)
- return (DDI_FAILURE);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_get_sleep_flags(handle));
}
@@ -872,9 +908,9 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_sync(dip, rdip, handle, off, len,
cache_flags));
}
@@ -884,9 +920,9 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp,
cookiep, ccountp));
}
@@ -895,9 +931,9 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_map(dip, rdip, dmareq, handlep));
}
@@ -906,14 +942,34 @@ 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);
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
return (nexops->nops_dma_mctl(dip, rdip, handle, request, offp, lenp,
objpp, cache_flags));
}
int
+iommulib_iommu_dmahdl_setprivate(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_handle_t handle, void *priv)
+{
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
+ return (nexops->nops_dmahdl_setprivate(dip, rdip, handle, priv));
+}
+
+void *
+iommulib_iommu_dmahdl_getprivate(dev_info_t *dip, dev_info_t *rdip,
+ ddi_dma_handle_t handle)
+{
+ iommulib_nexops_t *nexops;
+
+ nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops;
+ return (nexops->nops_dmahdl_getprivate(dip, rdip, handle));
+}
+
+int
iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp)
{
iommulib_unit_t *unitp;