[v2,1/2] iommu: Use mutex instead of spinlock for iommu_device_list

Message ID 20240126105341.78086-2-baolu.lu@linux.intel.com
State New
Headers
Series Use right iommu_ops for mock device |

Commit Message

Baolu Lu Jan. 26, 2024, 10:53 a.m. UTC
  The iommu_device_lock spinlock was used to protect the iommu device
list. However, there is no requirement to access the iommu device
list in interrupt context. Therefore, a mutex is sufficient.

This also prepares for the next change, which will iterate the iommu
device list and call the probe callback within the locking area.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/iommu/iommu.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)
  

Comments

Tian, Kevin Jan. 29, 2024, 8:04 a.m. UTC | #1
> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Friday, January 26, 2024 6:54 PM
> 
> The iommu_device_lock spinlock was used to protect the iommu device
> list. However, there is no requirement to access the iommu device
> list in interrupt context. Therefore, a mutex is sufficient.

I don't think that interrupt is the reason for spinlock otherwise
spin_lock_irqsave() should be used instead.

> 
> This also prepares for the next change, which will iterate the iommu
> device list and call the probe callback within the locking area.
> 

Given the touched paths are all slow paths:

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
  
Jason Gunthorpe Jan. 29, 2024, 2:57 p.m. UTC | #2
On Mon, Jan 29, 2024 at 08:04:35AM +0000, Tian, Kevin wrote:
> > From: Lu Baolu <baolu.lu@linux.intel.com>
> > Sent: Friday, January 26, 2024 6:54 PM
> > 
> > The iommu_device_lock spinlock was used to protect the iommu device
> > list. However, there is no requirement to access the iommu device
> > list in interrupt context. Therefore, a mutex is sufficient.
> 
> I don't think that interrupt is the reason for spinlock otherwise
> spin_lock_irqsave() should be used instead.

Right, there is no touch of this from an interrupt

I suspect it is following the the general kernel wisdom that a
spinlock is better if the critical sections are very small.

Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>

Jason
  

Patch

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 68e648b55767..0af0b5544072 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -146,7 +146,7 @@  struct iommu_group_attribute iommu_group_attr_##_name =		\
 	container_of(_kobj, struct iommu_group, kobj)
 
 static LIST_HEAD(iommu_device_list);
-static DEFINE_SPINLOCK(iommu_device_lock);
+static DEFINE_MUTEX(iommu_device_lock);
 
 static const struct bus_type * const iommu_buses[] = {
 	&platform_bus_type,
@@ -262,9 +262,9 @@  int iommu_device_register(struct iommu_device *iommu,
 	if (hwdev)
 		iommu->fwnode = dev_fwnode(hwdev);
 
-	spin_lock(&iommu_device_lock);
+	mutex_lock(&iommu_device_lock);
 	list_add_tail(&iommu->list, &iommu_device_list);
-	spin_unlock(&iommu_device_lock);
+	mutex_unlock(&iommu_device_lock);
 
 	for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++)
 		err = bus_iommu_probe(iommu_buses[i]);
@@ -279,9 +279,9 @@  void iommu_device_unregister(struct iommu_device *iommu)
 	for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++)
 		bus_for_each_dev(iommu_buses[i], NULL, iommu, remove_iommu_group);
 
-	spin_lock(&iommu_device_lock);
+	mutex_lock(&iommu_device_lock);
 	list_del(&iommu->list);
-	spin_unlock(&iommu_device_lock);
+	mutex_unlock(&iommu_device_lock);
 
 	/* Pairs with the alloc in generic_single_device_group() */
 	iommu_group_put(iommu->singleton_group);
@@ -316,9 +316,9 @@  int iommu_device_register_bus(struct iommu_device *iommu,
 	if (err)
 		return err;
 
-	spin_lock(&iommu_device_lock);
+	mutex_lock(&iommu_device_lock);
 	list_add_tail(&iommu->list, &iommu_device_list);
-	spin_unlock(&iommu_device_lock);
+	mutex_unlock(&iommu_device_lock);
 
 	err = bus_iommu_probe(bus);
 	if (err) {
@@ -2033,9 +2033,9 @@  bool iommu_present(const struct bus_type *bus)
 
 	for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
 		if (iommu_buses[i] == bus) {
-			spin_lock(&iommu_device_lock);
+			mutex_lock(&iommu_device_lock);
 			ret = !list_empty(&iommu_device_list);
-			spin_unlock(&iommu_device_lock);
+			mutex_unlock(&iommu_device_lock);
 		}
 	}
 	return ret;
@@ -2983,13 +2983,13 @@  const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
 	const struct iommu_ops *ops = NULL;
 	struct iommu_device *iommu;
 
-	spin_lock(&iommu_device_lock);
+	mutex_lock(&iommu_device_lock);
 	list_for_each_entry(iommu, &iommu_device_list, list)
 		if (iommu->fwnode == fwnode) {
 			ops = iommu->ops;
 			break;
 		}
-	spin_unlock(&iommu_device_lock);
+	mutex_unlock(&iommu_device_lock);
 	return ops;
 }