#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/iommu.h>
+++ ++#include <linux/idr.h>
+++ ++#include <linux/notifier.h>
+++ ++#include <linux/err.h>
+++ ++
+++ ++static struct kset *iommu_group_kset;
+++ ++static struct ida iommu_group_ida;
+++ ++static struct mutex iommu_group_mutex;
+++ ++
+++ ++struct iommu_group {
+++ ++ struct kobject kobj;
+++ ++ struct kobject *devices_kobj;
+++ ++ struct list_head devices;
+++ ++ struct mutex mutex;
+++ ++ struct blocking_notifier_head notifier;
+++ ++ void *iommu_data;
+++ ++ void (*iommu_data_release)(void *iommu_data);
+++ ++ char *name;
+++ ++ int id;
+++ ++};
+++ ++
+++ ++struct iommu_device {
+++ ++ struct list_head list;
+++ ++ struct device *dev;
+++ ++ char *name;
+++ ++};
+++ ++
+++ ++struct iommu_group_attribute {
+++ ++ struct attribute attr;
+++ ++ ssize_t (*show)(struct iommu_group *group, char *buf);
+++ ++ ssize_t (*store)(struct iommu_group *group,
+++ ++ const char *buf, size_t count);
+++ ++};
+++ ++
+++ ++#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
+++ ++struct iommu_group_attribute iommu_group_attr_##_name = \
+++ ++ __ATTR(_name, _mode, _show, _store)
+++ ++
+++ ++#define to_iommu_group_attr(_attr) \
+++ ++ container_of(_attr, struct iommu_group_attribute, attr)
+++ ++#define to_iommu_group(_kobj) \
+++ ++ container_of(_kobj, struct iommu_group, kobj)
--- --static ssize_t show_iommu_group(struct device *dev,
--- -- struct device_attribute *attr, char *buf)
+++ ++static ssize_t iommu_group_attr_show(struct kobject *kobj,
+++ ++ struct attribute *__attr, char *buf)
{
--- -- unsigned int groupid;
+++ ++ struct iommu_group_attribute *attr = to_iommu_group_attr(__attr);
+++ ++ struct iommu_group *group = to_iommu_group(kobj);
+++ ++ ssize_t ret = -EIO;
--- -- if (iommu_device_group(dev, &groupid))
--- -- return 0;
+++ ++ if (attr->show)
+++ ++ ret = attr->show(group, buf);
+++ ++ return ret;
+++ ++}
+++ +
- return sprintf(buf, "%u", groupid);
+++ ++static ssize_t iommu_group_attr_store(struct kobject *kobj,
+++ ++ struct attribute *__attr,
+++ ++ const char *buf, size_t count)
+++ ++{
+++ ++ struct iommu_group_attribute *attr = to_iommu_group_attr(__attr);
+++ ++ struct iommu_group *group = to_iommu_group(kobj);
+++ ++ ssize_t ret = -EIO;
+++ ++
+++ ++ if (attr->store)
+++ ++ ret = attr->store(group, buf, count);
+++ ++ return ret;
+++ + }
-static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL);
+++ +
-static int add_iommu_group(struct device *dev, void *data)
+++ ++static const struct sysfs_ops iommu_group_sysfs_ops = {
+++ ++ .show = iommu_group_attr_show,
+++ ++ .store = iommu_group_attr_store,
+++ ++};
+
--- - return sprintf(buf, "%u", groupid);
+++ ++static int iommu_group_create_file(struct iommu_group *group,
+++ ++ struct iommu_group_attribute *attr)
+++ ++{
+++ ++ return sysfs_create_file(&group->kobj, &attr->attr);
+}
--- - static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL);
+
--- - static int add_iommu_group(struct device *dev, void *data)
+++ ++static void iommu_group_remove_file(struct iommu_group *group,
+++ ++ struct iommu_group_attribute *attr)
+++ + {
- unsigned int groupid;
+++ ++ sysfs_remove_file(&group->kobj, &attr->attr);
+++ ++}
+++ ++
+++ ++static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf)
+++ ++{
+++ ++ return sprintf(buf, "%s\n", group->name);
+++ ++}
+++ ++
+++ ++static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL);
+++ +
- if (iommu_device_group(dev, &groupid) == 0)
- return device_create_file(dev, &dev_attr_iommu_group);
+++ ++static void iommu_group_release(struct kobject *kobj)
+++ ++{
+++ ++ struct iommu_group *group = to_iommu_group(kobj);
+++ ++
+++ ++ if (group->iommu_data_release)
+++ ++ group->iommu_data_release(group->iommu_data);
+++ ++
+++ ++ mutex_lock(&iommu_group_mutex);
+++ ++ ida_remove(&iommu_group_ida, group->id);
+++ ++ mutex_unlock(&iommu_group_mutex);
+++ ++
+++ ++ kfree(group->name);
+++ ++ kfree(group);
+++ ++}
+++ ++
+++ ++static struct kobj_type iommu_group_ktype = {
+++ ++ .sysfs_ops = &iommu_group_sysfs_ops,
+++ ++ .release = iommu_group_release,
+++ ++};
+++ ++
+++ ++/**
+++ ++ * iommu_group_alloc - Allocate a new group
+++ ++ * @name: Optional name to associate with group, visible in sysfs
+++ ++ *
+++ ++ * This function is called by an iommu driver to allocate a new iommu
+++ ++ * group. The iommu group represents the minimum granularity of the iommu.
+++ ++ * Upon successful return, the caller holds a reference to the supplied
+++ ++ * group in order to hold the group until devices are added. Use
+++ ++ * iommu_group_put() to release this extra reference count, allowing the
+++ ++ * group to be automatically reclaimed once it has no devices or external
+++ ++ * references.
+++ ++ */
+++ ++struct iommu_group *iommu_group_alloc(void)
+++ ++{
+++ ++ struct iommu_group *group;
+++ ++ int ret;
+++ ++
+++ ++ group = kzalloc(sizeof(*group), GFP_KERNEL);
+++ ++ if (!group)
+++ ++ return ERR_PTR(-ENOMEM);
+++ ++
+++ ++ group->kobj.kset = iommu_group_kset;
+++ ++ mutex_init(&group->mutex);
+++ ++ INIT_LIST_HEAD(&group->devices);
+++ ++ BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);
+++ ++
+++ ++ mutex_lock(&iommu_group_mutex);
+++ ++
+++ ++again:
+++ ++ if (unlikely(0 == ida_pre_get(&iommu_group_ida, GFP_KERNEL))) {
+++ ++ kfree(group);
+++ ++ mutex_unlock(&iommu_group_mutex);
+++ ++ return ERR_PTR(-ENOMEM);
+++ ++ }
+++ ++
+++ ++ if (-EAGAIN == ida_get_new(&iommu_group_ida, &group->id))
+++ ++ goto again;
+++ ++
+++ ++ mutex_unlock(&iommu_group_mutex);
+++ ++
+++ ++ ret = kobject_init_and_add(&group->kobj, &iommu_group_ktype,
+++ ++ NULL, "%d", group->id);
+++ ++ if (ret) {
+++ ++ mutex_lock(&iommu_group_mutex);
+++ ++ ida_remove(&iommu_group_ida, group->id);
+++ ++ mutex_unlock(&iommu_group_mutex);
+++ ++ kfree(group);
+++ ++ return ERR_PTR(ret);
+++ ++ }
+++ ++
+++ ++ group->devices_kobj = kobject_create_and_add("devices", &group->kobj);
+++ ++ if (!group->devices_kobj) {
+++ ++ kobject_put(&group->kobj); /* triggers .release & free */
+++ ++ return ERR_PTR(-ENOMEM);
+++ ++ }
+++ ++
+++ ++ /*
+++ ++ * The devices_kobj holds a reference on the group kobject, so
+++ ++ * as long as that exists so will the group. We can therefore
+++ ++ * use the devices_kobj for reference counting.
+++ ++ */
+++ ++ kobject_put(&group->kobj);
+++ ++
+++ ++ return group;
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_alloc);
+++ ++
+++ ++/**
+++ ++ * iommu_group_get_iommudata - retrieve iommu_data registered for a group
+++ ++ * @group: the group
+++ ++ *
+++ ++ * iommu drivers can store data in the group for use when doing iommu
+++ ++ * operations. This function provides a way to retrieve it. Caller
+++ ++ * should hold a group reference.
+++ ++ */
+++ ++void *iommu_group_get_iommudata(struct iommu_group *group)
+++ ++{
+++ ++ return group->iommu_data;
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_get_iommudata);
+++ ++
+++ ++/**
+++ ++ * iommu_group_set_iommudata - set iommu_data for a group
+++ ++ * @group: the group
+++ ++ * @iommu_data: new data
+++ ++ * @release: release function for iommu_data
+++ ++ *
+++ ++ * iommu drivers can store data in the group for use when doing iommu
+++ ++ * operations. This function provides a way to set the data after
+++ ++ * the group has been allocated. Caller should hold a group reference.
+++ ++ */
+++ ++void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data,
+++ ++ void (*release)(void *iommu_data))
+{
--- - unsigned int groupid;
+++ ++ group->iommu_data = iommu_data;
+++ ++ group->iommu_data_release = release;
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_set_iommudata);
+
--- - if (iommu_device_group(dev, &groupid) == 0)
--- - return device_create_file(dev, &dev_attr_iommu_group);
+++ ++/**
+++ ++ * iommu_group_set_name - set name for a group
+++ ++ * @group: the group
+++ ++ * @name: name
+++ ++ *
+++ ++ * Allow iommu driver to set a name for a group. When set it will
+++ ++ * appear in a name attribute file under the group in sysfs.
+++ ++ */
+++ ++int iommu_group_set_name(struct iommu_group *group, const char *name)
+++ ++{
+++ ++ int ret;
+++ ++
+++ ++ if (group->name) {
+++ ++ iommu_group_remove_file(group, &iommu_group_attr_name);
+++ ++ kfree(group->name);
+++ ++ group->name = NULL;
+++ ++ if (!name)
+++ ++ return 0;
+++ ++ }
+++ ++
+++ ++ group->name = kstrdup(name, GFP_KERNEL);
+++ ++ if (!group->name)
+++ ++ return -ENOMEM;
+++ ++
+++ ++ ret = iommu_group_create_file(group, &iommu_group_attr_name);
+++ ++ if (ret) {
+++ ++ kfree(group->name);
+++ ++ group->name = NULL;
+++ ++ return ret;
+++ ++ }
return 0;
}
-static int remove_iommu_group(struct device *dev)
+++ ++EXPORT_SYMBOL_GPL(iommu_group_set_name);
+++ +
- unsigned int groupid;
+++ ++/**
+++ ++ * iommu_group_add_device - add a device to an iommu group
+++ ++ * @group: the group into which to add the device (reference should be held)
+++ ++ * @dev: the device
+++ ++ *
+++ ++ * This function is called by an iommu driver to add a device into a
+++ ++ * group. Adding a device increments the group reference count.
+++ ++ */
+++ ++int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+++ + {
- if (iommu_device_group(dev, &groupid) == 0)
- device_remove_file(dev, &dev_attr_iommu_group);
+++ ++ int ret, i = 0;
+++ ++ struct iommu_device *device;
+++ ++
+++ ++ device = kzalloc(sizeof(*device), GFP_KERNEL);
+++ ++ if (!device)
+++ ++ return -ENOMEM;
+++ ++
+++ ++ device->dev = dev;
+++ ++
+++ ++ ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group");
+++ ++ if (ret) {
+++ ++ kfree(device);
+++ ++ return ret;
+++ ++ }
+++ ++
+++ ++ device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
+++ ++rename:
+++ ++ if (!device->name) {
+++ ++ sysfs_remove_link(&dev->kobj, "iommu_group");
+++ ++ kfree(device);
+++ ++ return -ENOMEM;
+++ ++ }
+++ +
-static int iommu_device_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
+++ ++ ret = sysfs_create_link_nowarn(group->devices_kobj,
+++ ++ &dev->kobj, device->name);
+++ ++ if (ret) {
+++ ++ kfree(device->name);
+++ ++ if (ret == -EEXIST && i >= 0) {
+++ ++ /*
+++ ++ * Account for the slim chance of collision
+++ ++ * and append an instance to the name.
+++ ++ */
+++ ++ device->name = kasprintf(GFP_KERNEL, "%s.%d",
+++ ++ kobject_name(&dev->kobj), i++);
+++ ++ goto rename;
+++ ++ }
+++ ++
+++ ++ sysfs_remove_link(&dev->kobj, "iommu_group");
+++ ++ kfree(device);
+++ ++ return ret;
+++ ++ }
+++ ++
+++ ++ kobject_get(group->devices_kobj);
+++ ++
+++ ++ dev->iommu_group = group;
+++ ++
+++ ++ mutex_lock(&group->mutex);
+++ ++ list_add_tail(&device->list, &group->devices);
+++ ++ mutex_unlock(&group->mutex);
+++ +
+++ ++ /* Notify any listeners about change to group. */
+++ ++ blocking_notifier_call_chain(&group->notifier,
+++ ++ IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev);
+++ + return 0;
+++ + }
+++ ++EXPORT_SYMBOL_GPL(iommu_group_add_device);
+++ +
--- - static int remove_iommu_group(struct device *dev)
+++ ++/**
+++ ++ * iommu_group_remove_device - remove a device from it's current group
+++ ++ * @dev: device to be removed
+++ ++ *
+++ ++ * This function is called by an iommu driver to remove the device from
+++ ++ * it's current group. This decrements the iommu group reference count.
+++ ++ */
+++ ++void iommu_group_remove_device(struct device *dev)
+++ ++{
+++ ++ struct iommu_group *group = dev->iommu_group;
+++ ++ struct iommu_device *tmp_device, *device = NULL;
+++ ++
+++ ++ /* Pre-notify listeners that a device is being removed. */
+++ ++ blocking_notifier_call_chain(&group->notifier,
+++ ++ IOMMU_GROUP_NOTIFY_DEL_DEVICE, dev);
+++ ++
+++ ++ mutex_lock(&group->mutex);
+++ ++ list_for_each_entry(tmp_device, &group->devices, list) {
+++ ++ if (tmp_device->dev == dev) {
+++ ++ device = tmp_device;
+++ ++ list_del(&device->list);
+++ ++ break;
+++ ++ }
+++ ++ }
+++ ++ mutex_unlock(&group->mutex);
+++ ++
+++ ++ if (!device)
+++ ++ return;
+++ ++
+++ ++ sysfs_remove_link(group->devices_kobj, device->name);
+++ ++ sysfs_remove_link(&dev->kobj, "iommu_group");
+++ ++
+++ ++ kfree(device->name);
+++ ++ kfree(device);
+++ ++ dev->iommu_group = NULL;
+++ ++ kobject_put(group->devices_kobj);
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_remove_device);
+++ ++
+++ ++/**
+++ ++ * iommu_group_for_each_dev - iterate over each device in the group
+++ ++ * @group: the group
+++ ++ * @data: caller opaque data to be passed to callback function
+++ ++ * @fn: caller supplied callback function
+++ ++ *
+++ ++ * This function is called by group users to iterate over group devices.
+++ ++ * Callers should hold a reference count to the group during callback.
+++ ++ * The group->mutex is held across callbacks, which will block calls to
+++ ++ * iommu_group_add/remove_device.
+++ ++ */
+++ ++int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+++ ++ int (*fn)(struct device *, void *))
+++ ++{
+++ ++ struct iommu_device *device;
+++ ++ int ret = 0;
+++ ++
+++ ++ mutex_lock(&group->mutex);
+++ ++ list_for_each_entry(device, &group->devices, list) {
+++ ++ ret = fn(device->dev, data);
+++ ++ if (ret)
+++ ++ break;
+++ ++ }
+++ ++ mutex_unlock(&group->mutex);
+++ ++ return ret;
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_for_each_dev);
+++ ++
+++ ++/**
+++ ++ * iommu_group_get - Return the group for a device and increment reference
+++ ++ * @dev: get the group that this device belongs to
+++ ++ *
+++ ++ * This function is called by iommu drivers and users to get the group
+++ ++ * for the specified device. If found, the group is returned and the group
+++ ++ * reference in incremented, else NULL.
+++ ++ */
+++ ++struct iommu_group *iommu_group_get(struct device *dev)
+++ ++{
+++ ++ struct iommu_group *group = dev->iommu_group;
+++ ++
+++ ++ if (group)
+++ ++ kobject_get(group->devices_kobj);
+++ ++
+++ ++ return group;
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_get);
+++ ++
+++ ++/**
+++ ++ * iommu_group_put - Decrement group reference
+++ ++ * @group: the group to use
+++ ++ *
+++ ++ * This function is called by iommu drivers and users to release the
+++ ++ * iommu group. Once the reference count is zero, the group is released.
+++ ++ */
+++ ++void iommu_group_put(struct iommu_group *group)
+++ ++{
+++ ++ if (group)
+++ ++ kobject_put(group->devices_kobj);
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_put);
+++ ++
+++ ++/**
+++ ++ * iommu_group_register_notifier - Register a notifier for group changes
+++ ++ * @group: the group to watch
+++ ++ * @nb: notifier block to signal
+++ ++ *
+++ ++ * This function allows iommu group users to track changes in a group.
+++ ++ * See include/linux/iommu.h for actions sent via this notifier. Caller
+++ ++ * should hold a reference to the group throughout notifier registration.
+++ ++ */
+++ ++int iommu_group_register_notifier(struct iommu_group *group,
+++ ++ struct notifier_block *nb)
+++ ++{
+++ ++ return blocking_notifier_chain_register(&group->notifier, nb);
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_register_notifier);
+++ ++
+++ ++/**
+++ ++ * iommu_group_unregister_notifier - Unregister a notifier
+++ ++ * @group: the group to watch
+++ ++ * @nb: notifier block to signal
+++ ++ *
+++ ++ * Unregister a previously registered group notifier block.
+++ ++ */
+++ ++int iommu_group_unregister_notifier(struct iommu_group *group,
+++ ++ struct notifier_block *nb)
+++ ++{
+++ ++ return blocking_notifier_chain_unregister(&group->notifier, nb);
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_unregister_notifier);
+++ ++
+++ ++/**
+++ ++ * iommu_group_id - Return ID for a group
+++ ++ * @group: the group to ID
+++ ++ *
+++ ++ * Return the unique ID for the group matching the sysfs group number.
+++ ++ */
+++ ++int iommu_group_id(struct iommu_group *group)
+++ ++{
+++ ++ return group->id;
+++ ++}
+++ ++EXPORT_SYMBOL_GPL(iommu_group_id);
+
--- - unsigned int groupid;
+++ ++static int add_iommu_group(struct device *dev, void *data)
+{
--- - if (iommu_device_group(dev, &groupid) == 0)
--- - device_remove_file(dev, &dev_attr_iommu_group);
+++ ++ struct iommu_ops *ops = data;
+++ ++
+++ ++ if (!ops->add_device)
+++ ++ return -ENODEV;
+
--- - static int iommu_device_notifier(struct notifier_block *nb,
--- - unsigned long action, void *data)
+++ ++ WARN_ON(dev->iommu_group);
+++ ++
+++ ++ ops->add_device(dev);
+
+ return 0;
+}
+
+++ ++static int iommu_bus_notifier(struct notifier_block *nb,
+++ ++ unsigned long action, void *data)
{
struct device *dev = data;
+++ ++ struct iommu_ops *ops = dev->bus->iommu_ops;
+++ ++ struct iommu_group *group;
+++ ++ unsigned long group_action = 0;
+++ ++
+++ ++ /*
+++ ++ * ADD/DEL call into iommu driver ops if provided, which may
+++ ++ * result in ADD/DEL notifiers to group->notifier
+++ ++ */
+++ ++ if (action == BUS_NOTIFY_ADD_DEVICE) {
+++ ++ if (ops->add_device)
+++ ++ return ops->add_device(dev);
+++ ++ } else if (action == BUS_NOTIFY_DEL_DEVICE) {
+++ ++ if (ops->remove_device && dev->iommu_group) {
+++ ++ ops->remove_device(dev);
+++ ++ return 0;
+++ ++ }
+++ ++ }
+++ ++
+++ ++ /*
+++ ++ * Remaining BUS_NOTIFYs get filtered and republished to the
+++ ++ * group, if anyone is listening
+++ ++ */
+++ ++ group = iommu_group_get(dev);
+++ ++ if (!group)
+++ ++ return 0;
+++ ++
+++ ++ switch (action) {
+++ ++ case BUS_NOTIFY_BIND_DRIVER:
+++ ++ group_action = IOMMU_GROUP_NOTIFY_BIND_DRIVER;
+++ ++ break;
+++ ++ case BUS_NOTIFY_BOUND_DRIVER:
+++ ++ group_action = IOMMU_GROUP_NOTIFY_BOUND_DRIVER;
+++ ++ break;
+++ ++ case BUS_NOTIFY_UNBIND_DRIVER:
+++ ++ group_action = IOMMU_GROUP_NOTIFY_UNBIND_DRIVER;
+++ ++ break;
+++ ++ case BUS_NOTIFY_UNBOUND_DRIVER:
+++ ++ group_action = IOMMU_GROUP_NOTIFY_UNBOUND_DRIVER;
+++ ++ break;
+++ ++ }
--- -- if (action == BUS_NOTIFY_ADD_DEVICE)
--- -- return add_iommu_group(dev, NULL);
--- -- else if (action == BUS_NOTIFY_DEL_DEVICE)
--- -- return remove_iommu_group(dev);
+++ ++ if (group_action)
+++ ++ blocking_notifier_call_chain(&group->notifier,
+++ ++ group_action, dev);
+++ ++ iommu_group_put(group);
return 0;
}
}
EXPORT_SYMBOL_GPL(iommu_unmap);
--- --int iommu_device_group(struct device *dev, unsigned int *groupid)
+++ ++static int __init iommu_init(void)
{
--- -- if (iommu_present(dev->bus) && dev->bus->iommu_ops->device_group)
--- -- return dev->bus->iommu_ops->device_group(dev, groupid);
+++ ++ iommu_group_kset = kset_create_and_add("iommu_groups",
+++ ++ NULL, kernel_kobj);
+++ ++ ida_init(&iommu_group_ida);
+++ ++ mutex_init(&iommu_group_mutex);
+++ ++
+++ ++ BUG_ON(!iommu_group_kset);
+++ +
- return -ENODEV;
+++ ++ return 0;
+++ + }
-EXPORT_SYMBOL_GPL(iommu_device_group);
+++ ++subsys_initcall(iommu_init);
+++++
+++++ int iommu_domain_get_attr(struct iommu_domain *domain,
+++++ enum iommu_attr attr, void *data)
+++++ {
+++++ struct iommu_domain_geometry *geometry;
+++++ int ret = 0;
+++++
+++++ switch (attr) {
+++++ case DOMAIN_ATTR_GEOMETRY:
+++++ geometry = data;
+++++ *geometry = domain->geometry;
+++++
+++++ break;
+++++ default:
+++++ if (!domain->ops->domain_get_attr)
+++++ return -EINVAL;
+++++
+++++ ret = domain->ops->domain_get_attr(domain, attr, data);
+++++ }
+++++
+++++ return ret;
+++++ }
+++++ EXPORT_SYMBOL_GPL(iommu_domain_get_attr);
+++++
+++++ int iommu_domain_set_attr(struct iommu_domain *domain,
+++++ enum iommu_attr attr, void *data)
+++++ {
+++++ if (!domain->ops->domain_set_attr)
+++++ return -EINVAL;
+
--- - return -ENODEV;
+++++ return domain->ops->domain_set_attr(domain, attr, data);
+ }
--- - EXPORT_SYMBOL_GPL(iommu_device_group);
+++++ EXPORT_SYMBOL_GPL(iommu_domain_set_attr);
* @unmap: unmap a physically contiguous memory region from an iommu domain
* @iova_to_phys: translate iova to physical address
* @domain_has_cap: domain capabilities query
----- * @commit: commit iommu domain
+++ ++ * @add_device: add device to iommu grouping
+++ ++ * @remove_device: remove device from iommu grouping
+++++ * @domain_get_attr: Query domain attributes
+++++ * @domain_set_attr: Change domain attributes
* @pgsize_bitmap: bitmap of supported page sizes
*/
struct iommu_ops {
unsigned long iova);
int (*domain_has_cap)(struct iommu_domain *domain,
unsigned long cap);
+++ ++ int (*add_device)(struct device *dev);
+++ ++ void (*remove_device)(struct device *dev);
+ int (*device_group)(struct device *dev, unsigned int *groupid);
+++++ int (*domain_get_attr)(struct iommu_domain *domain,
+++++ enum iommu_attr attr, void *data);
+++++ int (*domain_set_attr)(struct iommu_domain *domain,
+++++ enum iommu_attr attr, void *data);
unsigned long pgsize_bitmap;
};
unsigned long cap);
extern void iommu_set_fault_handler(struct iommu_domain *domain,
iommu_fault_handler_t handler, void *token);
--- --extern int iommu_device_group(struct device *dev, unsigned int *groupid);
+++ ++
+++ ++extern int iommu_attach_group(struct iommu_domain *domain,
+++ ++ struct iommu_group *group);
+++ ++extern void iommu_detach_group(struct iommu_domain *domain,
+++ ++ struct iommu_group *group);
+++ ++extern struct iommu_group *iommu_group_alloc(void);
+++ ++extern void *iommu_group_get_iommudata(struct iommu_group *group);
+++ ++extern void iommu_group_set_iommudata(struct iommu_group *group,
+++ ++ void *iommu_data,
+++ ++ void (*release)(void *iommu_data));
+++ ++extern int iommu_group_set_name(struct iommu_group *group, const char *name);
+++ ++extern int iommu_group_add_device(struct iommu_group *group,
+++ ++ struct device *dev);
+++ ++extern void iommu_group_remove_device(struct device *dev);
+++ ++extern int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+++ ++ int (*fn)(struct device *, void *));
+++ ++extern struct iommu_group *iommu_group_get(struct device *dev);
+++ ++extern void iommu_group_put(struct iommu_group *group);
+++ ++extern int iommu_group_register_notifier(struct iommu_group *group,
+++ ++ struct notifier_block *nb);
+++ ++extern int iommu_group_unregister_notifier(struct iommu_group *group,
+++ ++ struct notifier_block *nb);
+++ ++extern int iommu_group_id(struct iommu_group *group);
+++ +
+++++ extern int iommu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr,
+++++ void *data);
+++++ extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr,
+++++ void *data);
+
/**
* report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
* @domain: the iommu domain where the fault has happened
{
}
--- --static inline int iommu_device_group(struct device *dev, unsigned int *groupid)
+++ ++int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
+++ ++{
+++ ++ return -ENODEV;
+++ ++}
+++ ++
+++ ++void iommu_detach_group(struct iommu_domain *domain, struct iommu_group *group)
+++ ++{
+++ ++}
+++ ++
+++ ++struct iommu_group *iommu_group_alloc(void)
+++ ++{
+++ ++ return ERR_PTR(-ENODEV);
+++ ++}
+++ ++
+++ ++void *iommu_group_get_iommudata(struct iommu_group *group)
+++ ++{
+++ ++ return NULL;
+++ ++}
+++ ++
+++ ++void iommu_group_set_iommudata(struct iommu_group *group, void *iommu_data,
+++ ++ void (*release)(void *iommu_data))
+++ ++{
+++ ++}
+++ ++
+++ ++int iommu_group_set_name(struct iommu_group *group, const char *name)
+++ ++{
+++ ++ return -ENODEV;
+++ ++}
+++ ++
+++ ++int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+++ ++{
+++ ++ return -ENODEV;
+++ ++}
+++ ++
+++ ++void iommu_group_remove_device(struct device *dev)
+++ ++{
+++ ++}
+++ ++
+++ ++int iommu_group_for_each_dev(struct iommu_group *group, void *data,
+++ ++ int (*fn)(struct device *, void *))
+++ ++{
+++ ++ return -ENODEV;
+++ ++}
+++ ++
+++ ++struct iommu_group *iommu_group_get(struct device *dev)
+++ ++{
+++ ++ return NULL;
+++ ++}
+++ ++
+++ ++void iommu_group_put(struct iommu_group *group)
+++ ++{
+++ ++}
+++ ++
+++ ++int iommu_group_register_notifier(struct iommu_group *group,
+++ ++ struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
+++ ++int iommu_group_unregister_notifier(struct iommu_group *group,
+++ ++ struct notifier_block *nb)
+++ ++{
+++ ++ return 0;
+++ ++}
+++ ++
+++ ++int iommu_group_id(struct iommu_group *group)
+++ + {
+++ + return -ENODEV;
+++ + }
+++++
+++++ static inline int iommu_domain_get_attr(struct iommu_domain *domain,
+++++ enum iommu_attr attr, void *data)
+++++ {
+++++ return -EINVAL;
+++++ }
+++++
+++++ static inline int iommu_domain_set_attr(struct iommu_domain *domain,
+++++ enum iommu_attr attr, void *data)
+++++ {
+++++ return -EINVAL;
+++++ }
+++++
#endif /* CONFIG_IOMMU_API */
#endif /* __LINUX_IOMMU_H */