/*
* 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
* 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 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
*/
#pragma ident "@(#)iommulib.c 1.6 08/09/07 SMI"
#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 {
void* ilu_data;
typedef struct iommulib_nex {
/* ********* Globals ************************ */
/* For IOMMU drivers */
/* IOMMU side: Following data protected by lock */
/* rootnex side data */
/* can be set atomically without lock */
/* debug flag */
static int iommulib_debug;
/*
* Module linkage information for the kernel.
*/
&mod_miscops, "IOMMU library module"
};
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (EBUSY);
}
iommulib_fini = 1;
return (mod_remove(&modlinkage));
}
int
{
}
/*
* Routines with iommulib_iommu_* are invoked from the
* IOMMU driver.
* Routines with iommulib_nex* are invoked from the
* nexus driver (typically rootnex)
*/
int
{
const char *f = "iommulib_nexus_register";
/*
* Root node is never busy held
*/
!DEVI_BUSY_OWNED(pdip))) {
"or busy held for nexops vector (%p). Failing registration",
f, (void *)nexops);
return (DDI_FAILURE);
}
"in nexops vector (%p). Failing NEXUS registration",
return (DDI_FAILURE);
}
"Failing registration for nexops vector: %p",
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
if (iommulib_fini == 1) {
"Failing NEXUS register.", f);
return (DDI_FAILURE);
}
/*
* nexus struct
*/
/*
* The nexus device won't be controlled by an IOMMU.
*/
(void *)nexops);
return (DDI_SUCCESS);
}
int
{
int instance;
const char *driver;
const char *f = "iommulib_nexus_unregister";
return (DDI_FAILURE);
/* A future enhancement would be to add ref-counts */
} else {
}
ddi_node_name(dip));
return (DDI_SUCCESS);
}
int
{
const char *vendor;
const char *f = "iommulib_register";
"in ops vector (%p). Failing registration", f, driver,
return (DDI_FAILURE);
}
switch (ops->ilops_vendor) {
case AMD_IOMMU:
vendor = "AMD";
break;
case INTEL_IOMMU:
vendor = "Intel";
break;
case INVALID_VENDOR:
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
default:
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
"Failing registration for ops vector: %p", f,
return (DDI_FAILURE);
}
if (iommulib_fini == 1) {
f);
return (DDI_FAILURE);
}
/*
* IOMMU unit
*/
/*
* The IOMMU device itself is not controlled by an IOMMU.
*/
"from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u",
unitp->ilu_unitid);
return (DDI_SUCCESS);
}
int
{
int instance;
const char *driver;
const char *f = "iommulib_unregister";
"unregister IOMMULIB unitid %u",
return (DDI_FAILURE);
}
unitp->ilu_unitid = 0;
} else {
}
return (DDI_SUCCESS);
}
int
{
const char *f = "iommulib_nex_open";
/* prevent use of IOMMU for AMD IOMMU's DMA */
return (DDI_ENOTSUP);
}
/*
* Use the probe entry point to determine in a hardware specific
* manner whether this dip is controlled by an IOMMU. If yes,
* return the handle corresponding to the IOMMU unit.
*/
break;
}
if (iommulib_debug) {
"controlled by an IOMMU: path=%s", f, driver,
}
return (DDI_ENOTSUP);
}
return (DDI_SUCCESS);
}
void
{
const char *driver;
int instance;
const char *f = "iommulib_nex_close";
if (iommulib_debug) {
}
}
int
{
/* No need to grab lock - the handle is reference counted */
}
int
{
int error;
/* No need to grab lock - the handle is reference counted */
rdip, dma_handle);
return (error);
}
int
{
/* No need to grab lock - the handle is reference counted */
}
int
{
/* No need to grab lock - the handle is reference counted */
dma_handle));
}
int
{
/* No need to grab lock - the handle is reference counted */
}
int
{
/* No need to grab lock - the handle is reference counted */
}
int
{
}
int
{
dma_handle, dmao));
}
/* Utility routines invoked by IOMMU drivers */
int
{
handlep));
}
int
{
}
int
{
}
int
{
}
void
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
cache_flags));
}
int
{
}
int
{
}
void *
{
}
int
{
return (DDI_SUCCESS);
}
{
return (dip);
}
{
return (ops);
}
void *
{
void *data;
return (data);
}