iommu: Add sysfs bindings for struct iommu_device

There is currently support for iommu sysfs bindings, but
those need to be implemented in the IOMMU drivers. Add a
more generic version of this by adding a struct device to
struct iommu_device and use that for the sysfs bindings.

Also convert the AMD and Intel IOMMU driver to make use of
it.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Joerg Roedel 2017-02-01 16:56:46 +01:00
parent b0119e8708
commit 39ab9555c2
8 changed files with 62 additions and 70 deletions

View File

@ -445,6 +445,7 @@ static void init_iommu_group(struct device *dev)
static int iommu_init_device(struct device *dev) static int iommu_init_device(struct device *dev)
{ {
struct iommu_dev_data *dev_data; struct iommu_dev_data *dev_data;
struct amd_iommu *iommu;
int devid; int devid;
if (dev->archdata.iommu) if (dev->archdata.iommu)
@ -454,6 +455,8 @@ static int iommu_init_device(struct device *dev)
if (devid < 0) if (devid < 0)
return devid; return devid;
iommu = amd_iommu_rlookup_table[devid];
dev_data = find_dev_data(devid); dev_data = find_dev_data(devid);
if (!dev_data) if (!dev_data)
return -ENOMEM; return -ENOMEM;
@ -469,8 +472,7 @@ static int iommu_init_device(struct device *dev)
dev->archdata.iommu = dev_data; dev->archdata.iommu = dev_data;
iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev, iommu_device_link(&iommu->iommu.dev, dev);
dev);
return 0; return 0;
} }
@ -495,13 +497,16 @@ static void iommu_ignore_device(struct device *dev)
static void iommu_uninit_device(struct device *dev) static void iommu_uninit_device(struct device *dev)
{ {
int devid;
struct iommu_dev_data *dev_data; struct iommu_dev_data *dev_data;
struct amd_iommu *iommu;
int devid;
devid = get_device_id(dev); devid = get_device_id(dev);
if (devid < 0) if (devid < 0)
return; return;
iommu = amd_iommu_rlookup_table[devid];
dev_data = search_dev_data(devid); dev_data = search_dev_data(devid);
if (!dev_data) if (!dev_data)
return; return;
@ -509,8 +514,7 @@ static void iommu_uninit_device(struct device *dev)
if (dev_data->domain) if (dev_data->domain)
detach_device(dev); detach_device(dev);
iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev, iommu_device_unlink(&iommu->iommu.dev, dev);
dev);
iommu_group_remove_device(dev); iommu_group_remove_device(dev);

View File

@ -1637,10 +1637,8 @@ static int iommu_init_pci(struct amd_iommu *iommu)
amd_iommu_erratum_746_workaround(iommu); amd_iommu_erratum_746_workaround(iommu);
amd_iommu_ats_write_check_workaround(iommu); amd_iommu_ats_write_check_workaround(iommu);
iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu, iommu_device_sysfs_add(&iommu->iommu, &iommu->dev->dev,
amd_iommu_groups, "ivhd%d", amd_iommu_groups, "ivhd%d", iommu->index);
iommu->index);
iommu_device_set_ops(&iommu->iommu, &amd_iommu_ops); iommu_device_set_ops(&iommu->iommu, &amd_iommu_ops);
iommu_device_register(&iommu->iommu); iommu_device_register(&iommu->iommu);

View File

@ -535,9 +535,6 @@ struct amd_iommu {
/* if one, we need to send a completion wait command */ /* if one, we need to send a completion wait command */
bool need_sync; bool need_sync;
/* IOMMU sysfs device */
struct device *iommu_dev;
/* Handle for IOMMU core code */ /* Handle for IOMMU core code */
struct iommu_device iommu; struct iommu_device iommu;

View File

@ -1078,14 +1078,11 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
raw_spin_lock_init(&iommu->register_lock); raw_spin_lock_init(&iommu->register_lock);
if (intel_iommu_enabled) { if (intel_iommu_enabled) {
iommu->iommu_dev = iommu_device_create(NULL, iommu, err = iommu_device_sysfs_add(&iommu->iommu, NULL,
intel_iommu_groups, intel_iommu_groups,
"%s", iommu->name); "%s", iommu->name);
if (err)
if (IS_ERR(iommu->iommu_dev)) {
err = PTR_ERR(iommu->iommu_dev);
goto err_unmap; goto err_unmap;
}
iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops); iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
@ -1109,7 +1106,7 @@ error:
static void free_iommu(struct intel_iommu *iommu) static void free_iommu(struct intel_iommu *iommu)
{ {
iommu_device_destroy(iommu->iommu_dev); iommu_device_sysfs_remove(&iommu->iommu);
iommu_device_unregister(&iommu->iommu); iommu_device_unregister(&iommu->iommu);
if (iommu->irq) { if (iommu->irq) {

View File

@ -4834,10 +4834,13 @@ int __init intel_iommu_init(void)
init_iommu_pm_ops(); init_iommu_pm_ops();
for_each_active_iommu(iommu, drhd) for_each_active_iommu(iommu, drhd) {
iommu->iommu_dev = iommu_device_create(NULL, iommu, iommu_device_sysfs_add(&iommu->iommu, NULL,
intel_iommu_groups, intel_iommu_groups,
"%s", iommu->name); "%s", iommu->name);
iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
iommu_device_register(&iommu->iommu);
}
bus_set_iommu(&pci_bus_type, &intel_iommu_ops); bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
bus_register_notifier(&pci_bus_type, &device_nb); bus_register_notifier(&pci_bus_type, &device_nb);
@ -5159,7 +5162,7 @@ static int intel_iommu_add_device(struct device *dev)
if (!iommu) if (!iommu)
return -ENODEV; return -ENODEV;
iommu_device_link(iommu->iommu_dev, dev); iommu_device_link(&iommu->iommu.dev, dev);
group = iommu_group_get_for_dev(dev); group = iommu_group_get_for_dev(dev);
@ -5181,7 +5184,7 @@ static void intel_iommu_remove_device(struct device *dev)
iommu_group_remove_device(dev); iommu_group_remove_device(dev);
iommu_device_unlink(iommu->iommu_dev, dev); iommu_device_unlink(&iommu->iommu.dev, dev);
} }
#ifdef CONFIG_INTEL_IOMMU_SVM #ifdef CONFIG_INTEL_IOMMU_SVM

View File

@ -50,54 +50,45 @@ static int __init iommu_dev_init(void)
postcore_initcall(iommu_dev_init); postcore_initcall(iommu_dev_init);
/* /*
* Create an IOMMU device and return a pointer to it. IOMMU specific * Init the struct device for the IOMMU. IOMMU specific attributes can
* attributes can be provided as an attribute group, allowing a unique * be provided as an attribute group, allowing a unique namespace per
* namespace per IOMMU type. * IOMMU type.
*/ */
struct device *iommu_device_create(struct device *parent, void *drvdata, int iommu_device_sysfs_add(struct iommu_device *iommu,
const struct attribute_group **groups, struct device *parent,
const char *fmt, ...) const struct attribute_group **groups,
const char *fmt, ...)
{ {
struct device *dev;
va_list vargs; va_list vargs;
int ret; int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); device_initialize(&iommu->dev);
if (!dev)
return ERR_PTR(-ENOMEM);
device_initialize(dev); iommu->dev.class = &iommu_class;
iommu->dev.parent = parent;
dev->class = &iommu_class; iommu->dev.groups = groups;
dev->parent = parent;
dev->groups = groups;
dev_set_drvdata(dev, drvdata);
va_start(vargs, fmt); va_start(vargs, fmt);
ret = kobject_set_name_vargs(&dev->kobj, fmt, vargs); ret = kobject_set_name_vargs(&iommu->dev.kobj, fmt, vargs);
va_end(vargs); va_end(vargs);
if (ret) if (ret)
goto error; goto error;
ret = device_add(dev); ret = device_add(&iommu->dev);
if (ret) if (ret)
goto error; goto error;
return dev; return 0;
error: error:
put_device(dev); put_device(&iommu->dev);
return ERR_PTR(ret); return ret;
} }
void iommu_device_destroy(struct device *dev) void iommu_device_sysfs_remove(struct iommu_device *iommu)
{ {
if (!dev || IS_ERR(dev)) device_unregister(&iommu->dev);
return;
device_unregister(dev);
} }
/* /*
* IOMMU drivers can indicate a device is managed by a given IOMMU using * IOMMU drivers can indicate a device is managed by a given IOMMU using
* this interface. A link to the device will be created in the "devices" * this interface. A link to the device will be created in the "devices"

View File

@ -440,7 +440,6 @@ struct intel_iommu {
struct irq_domain *ir_domain; struct irq_domain *ir_domain;
struct irq_domain *ir_msi_domain; struct irq_domain *ir_msi_domain;
#endif #endif
struct device *iommu_dev; /* IOMMU-sysfs device */
struct iommu_device iommu; /* IOMMU core code handle */ struct iommu_device iommu; /* IOMMU core code handle */
int node; int node;
u32 flags; /* Software defined flags */ u32 flags; /* Software defined flags */

View File

@ -209,14 +209,21 @@ struct iommu_ops {
* instance * instance
* @list: Used by the iommu-core to keep a list of registered iommus * @list: Used by the iommu-core to keep a list of registered iommus
* @ops: iommu-ops for talking to this iommu * @ops: iommu-ops for talking to this iommu
* @dev: struct device for sysfs handling
*/ */
struct iommu_device { struct iommu_device {
struct list_head list; struct list_head list;
const struct iommu_ops *ops; const struct iommu_ops *ops;
struct device dev;
}; };
int iommu_device_register(struct iommu_device *iommu); int iommu_device_register(struct iommu_device *iommu);
void iommu_device_unregister(struct iommu_device *iommu); void iommu_device_unregister(struct iommu_device *iommu);
int iommu_device_sysfs_add(struct iommu_device *iommu,
struct device *parent,
const struct attribute_group **groups,
const char *fmt, ...) __printf(4, 5);
void iommu_device_sysfs_remove(struct iommu_device *iommu);
static inline void iommu_device_set_ops(struct iommu_device *iommu, static inline void iommu_device_set_ops(struct iommu_device *iommu,
const struct iommu_ops *ops) const struct iommu_ops *ops)
@ -287,10 +294,6 @@ extern int iommu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr,
void *data); void *data);
extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr, extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr,
void *data); void *data);
struct device *iommu_device_create(struct device *parent, void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...) __printf(4, 5);
void iommu_device_destroy(struct device *dev);
int iommu_device_link(struct device *dev, struct device *link); int iommu_device_link(struct device *dev, struct device *link);
void iommu_device_unlink(struct device *dev, struct device *link); void iommu_device_unlink(struct device *dev, struct device *link);
@ -567,18 +570,6 @@ static inline int iommu_domain_set_attr(struct iommu_domain *domain,
return -EINVAL; return -EINVAL;
} }
static inline struct device *iommu_device_create(struct device *parent,
void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...)
{
return ERR_PTR(-ENODEV);
}
static inline void iommu_device_destroy(struct device *dev)
{
}
static inline int iommu_device_register(struct iommu_device *iommu) static inline int iommu_device_register(struct iommu_device *iommu)
{ {
return -ENODEV; return -ENODEV;
@ -593,6 +584,18 @@ static inline void iommu_device_unregister(struct iommu_device *iommu)
{ {
} }
static inline int iommu_device_sysfs_add(struct iommu_device *iommu,
struct device *parent,
const struct attribute_group **groups,
const char *fmt, ...)
{
return -ENODEV;
}
static inline void iommu_device_sysfs_remove(struct iommu_device *iommu)
{
}
static inline int iommu_device_link(struct device *dev, struct device *link) static inline int iommu_device_link(struct device *dev, struct device *link)
{ {
return -EINVAL; return -EINVAL;