mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									b0119e8708
								
							
						
					
					
						commit
						39ab9555c2
					
				
					 8 changed files with 62 additions and 70 deletions
				
			
		| 
						 | 
				
			
			@ -445,6 +445,7 @@ static void init_iommu_group(struct device *dev)
 | 
			
		|||
static int iommu_init_device(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct iommu_dev_data *dev_data;
 | 
			
		||||
	struct amd_iommu *iommu;
 | 
			
		||||
	int devid;
 | 
			
		||||
 | 
			
		||||
	if (dev->archdata.iommu)
 | 
			
		||||
| 
						 | 
				
			
			@ -454,6 +455,8 @@ static int iommu_init_device(struct device *dev)
 | 
			
		|||
	if (devid < 0)
 | 
			
		||||
		return devid;
 | 
			
		||||
 | 
			
		||||
	iommu = amd_iommu_rlookup_table[devid];
 | 
			
		||||
 | 
			
		||||
	dev_data = find_dev_data(devid);
 | 
			
		||||
	if (!dev_data)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
| 
						 | 
				
			
			@ -469,8 +472,7 @@ static int iommu_init_device(struct device *dev)
 | 
			
		|||
 | 
			
		||||
	dev->archdata.iommu = dev_data;
 | 
			
		||||
 | 
			
		||||
	iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
 | 
			
		||||
			  dev);
 | 
			
		||||
	iommu_device_link(&iommu->iommu.dev, dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -495,13 +497,16 @@ static void iommu_ignore_device(struct device *dev)
 | 
			
		|||
 | 
			
		||||
static void iommu_uninit_device(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int devid;
 | 
			
		||||
	struct iommu_dev_data *dev_data;
 | 
			
		||||
	struct amd_iommu *iommu;
 | 
			
		||||
	int devid;
 | 
			
		||||
 | 
			
		||||
	devid = get_device_id(dev);
 | 
			
		||||
	if (devid < 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	iommu = amd_iommu_rlookup_table[devid];
 | 
			
		||||
 | 
			
		||||
	dev_data = search_dev_data(devid);
 | 
			
		||||
	if (!dev_data)
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -509,8 +514,7 @@ static void iommu_uninit_device(struct device *dev)
 | 
			
		|||
	if (dev_data->domain)
 | 
			
		||||
		detach_device(dev);
 | 
			
		||||
 | 
			
		||||
	iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
 | 
			
		||||
			    dev);
 | 
			
		||||
	iommu_device_unlink(&iommu->iommu.dev, 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_ats_write_check_workaround(iommu);
 | 
			
		||||
 | 
			
		||||
	iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
 | 
			
		||||
					       amd_iommu_groups, "ivhd%d",
 | 
			
		||||
					       iommu->index);
 | 
			
		||||
 | 
			
		||||
	iommu_device_sysfs_add(&iommu->iommu, &iommu->dev->dev,
 | 
			
		||||
			       amd_iommu_groups, "ivhd%d", iommu->index);
 | 
			
		||||
	iommu_device_set_ops(&iommu->iommu, &amd_iommu_ops);
 | 
			
		||||
	iommu_device_register(&iommu->iommu);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -535,9 +535,6 @@ struct amd_iommu {
 | 
			
		|||
	/* if one, we need to send a completion wait command */
 | 
			
		||||
	bool need_sync;
 | 
			
		||||
 | 
			
		||||
	/* IOMMU sysfs device */
 | 
			
		||||
	struct device *iommu_dev;
 | 
			
		||||
 | 
			
		||||
	/* Handle for IOMMU core code */
 | 
			
		||||
	struct iommu_device iommu;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1078,14 +1078,11 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
 | 
			
		|||
	raw_spin_lock_init(&iommu->register_lock);
 | 
			
		||||
 | 
			
		||||
	if (intel_iommu_enabled) {
 | 
			
		||||
		iommu->iommu_dev = iommu_device_create(NULL, iommu,
 | 
			
		||||
						       intel_iommu_groups,
 | 
			
		||||
						       "%s", iommu->name);
 | 
			
		||||
 | 
			
		||||
		if (IS_ERR(iommu->iommu_dev)) {
 | 
			
		||||
			err = PTR_ERR(iommu->iommu_dev);
 | 
			
		||||
		err = iommu_device_sysfs_add(&iommu->iommu, NULL,
 | 
			
		||||
					     intel_iommu_groups,
 | 
			
		||||
					     "%s", iommu->name);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto err_unmap;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1109,7 +1106,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
 | 
			
		|||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
	if (iommu->irq) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4834,10 +4834,13 @@ int __init intel_iommu_init(void)
 | 
			
		|||
 | 
			
		||||
	init_iommu_pm_ops();
 | 
			
		||||
 | 
			
		||||
	for_each_active_iommu(iommu, drhd)
 | 
			
		||||
		iommu->iommu_dev = iommu_device_create(NULL, iommu,
 | 
			
		||||
						       intel_iommu_groups,
 | 
			
		||||
						       "%s", iommu->name);
 | 
			
		||||
	for_each_active_iommu(iommu, drhd) {
 | 
			
		||||
		iommu_device_sysfs_add(&iommu->iommu, NULL,
 | 
			
		||||
				       intel_iommu_groups,
 | 
			
		||||
				       "%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_register_notifier(&pci_bus_type, &device_nb);
 | 
			
		||||
| 
						 | 
				
			
			@ -5159,7 +5162,7 @@ static int intel_iommu_add_device(struct device *dev)
 | 
			
		|||
	if (!iommu)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	iommu_device_link(iommu->iommu_dev, dev);
 | 
			
		||||
	iommu_device_link(&iommu->iommu.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_device_unlink(iommu->iommu_dev, dev);
 | 
			
		||||
	iommu_device_unlink(&iommu->iommu.dev, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_INTEL_IOMMU_SVM
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,54 +50,45 @@ static int __init iommu_dev_init(void)
 | 
			
		|||
postcore_initcall(iommu_dev_init);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Create an IOMMU device and return a pointer to it.  IOMMU specific
 | 
			
		||||
 * attributes can be provided as an attribute group, allowing a unique
 | 
			
		||||
 * namespace per IOMMU type.
 | 
			
		||||
 * Init the struct device for the IOMMU. IOMMU specific attributes can
 | 
			
		||||
 * be provided as an attribute group, allowing a unique namespace per
 | 
			
		||||
 * IOMMU type.
 | 
			
		||||
 */
 | 
			
		||||
struct device *iommu_device_create(struct device *parent, void *drvdata,
 | 
			
		||||
				   const struct attribute_group **groups,
 | 
			
		||||
				   const char *fmt, ...)
 | 
			
		||||
int iommu_device_sysfs_add(struct iommu_device *iommu,
 | 
			
		||||
			   struct device *parent,
 | 
			
		||||
			   const struct attribute_group **groups,
 | 
			
		||||
			   const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	va_list vargs;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 | 
			
		||||
	if (!dev)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
	device_initialize(&iommu->dev);
 | 
			
		||||
 | 
			
		||||
	device_initialize(dev);
 | 
			
		||||
 | 
			
		||||
	dev->class = &iommu_class;
 | 
			
		||||
	dev->parent = parent;
 | 
			
		||||
	dev->groups = groups;
 | 
			
		||||
	dev_set_drvdata(dev, drvdata);
 | 
			
		||||
	iommu->dev.class = &iommu_class;
 | 
			
		||||
	iommu->dev.parent = parent;
 | 
			
		||||
	iommu->dev.groups = groups;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	ret = device_add(dev);
 | 
			
		||||
	ret = device_add(&iommu->dev);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	return dev;
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
	put_device(dev);
 | 
			
		||||
	return ERR_PTR(ret);
 | 
			
		||||
	put_device(&iommu->dev);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iommu_device_destroy(struct device *dev)
 | 
			
		||||
void iommu_device_sysfs_remove(struct iommu_device *iommu)
 | 
			
		||||
{
 | 
			
		||||
	if (!dev || IS_ERR(dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	device_unregister(dev);
 | 
			
		||||
	device_unregister(&iommu->dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -440,7 +440,6 @@ struct intel_iommu {
 | 
			
		|||
	struct irq_domain *ir_domain;
 | 
			
		||||
	struct irq_domain *ir_msi_domain;
 | 
			
		||||
#endif
 | 
			
		||||
	struct device	*iommu_dev; /* IOMMU-sysfs device */
 | 
			
		||||
	struct iommu_device iommu;  /* IOMMU core code handle */
 | 
			
		||||
	int		node;
 | 
			
		||||
	u32		flags;      /* Software defined flags */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -209,14 +209,21 @@ struct iommu_ops {
 | 
			
		|||
 *			 instance
 | 
			
		||||
 * @list: Used by the iommu-core to keep a list of registered iommus
 | 
			
		||||
 * @ops: iommu-ops for talking to this iommu
 | 
			
		||||
 * @dev: struct device for sysfs handling
 | 
			
		||||
 */
 | 
			
		||||
struct iommu_device {
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	const struct iommu_ops *ops;
 | 
			
		||||
	struct device dev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int  iommu_device_register(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,
 | 
			
		||||
					const struct iommu_ops *ops)
 | 
			
		||||
| 
						 | 
				
			
			@ -287,10 +294,6 @@ 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);
 | 
			
		||||
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);
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue