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:
Родитель
b0119e8708
Коммит
39ab9555c2
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче