Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iommu/amd: move wait_on_sem() out of spinlock

With iommu.strict=1, the existing completion wait path can cause soft
lockups under stressed environment, as wait_on_sem() busy-waits under the
spinlock with interrupts disabled.

Move the completion wait in iommu_completion_wait() out of the spinlock.
wait_on_sem() only polls the hardware-updated cmd_sem and does not require
iommu->lock, so holding the lock during the busy wait unnecessarily
increases contention and extends the time with interrupts disabled.

Signed-off-by: Ankit Soni <Ankit.Soni@amd.com>
Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>

authored by

Ankit Soni and committed by
Joerg Roedel
d2a0cac1 9ace4753

+18 -9
+18 -9
drivers/iommu/amd/iommu.c
··· 1185 1185 { 1186 1186 int i = 0; 1187 1187 1188 - while (*iommu->cmd_sem != data && i < LOOP_TIMEOUT) { 1188 + /* 1189 + * cmd_sem holds a monotonically non-decreasing completion sequence 1190 + * number. 1191 + */ 1192 + while ((__s64)(READ_ONCE(*iommu->cmd_sem) - data) < 0 && 1193 + i < LOOP_TIMEOUT) { 1189 1194 udelay(1); 1190 1195 i += 1; 1191 1196 } ··· 1442 1437 raw_spin_lock_irqsave(&iommu->lock, flags); 1443 1438 1444 1439 ret = __iommu_queue_command_sync(iommu, &cmd, false); 1440 + raw_spin_unlock_irqrestore(&iommu->lock, flags); 1441 + 1445 1442 if (ret) 1446 - goto out_unlock; 1443 + return ret; 1447 1444 1448 1445 ret = wait_on_sem(iommu, data); 1449 - 1450 - out_unlock: 1451 - raw_spin_unlock_irqrestore(&iommu->lock, flags); 1452 1446 1453 1447 return ret; 1454 1448 } ··· 3125 3121 raw_spin_lock_irqsave(&iommu->lock, flags); 3126 3122 ret = __iommu_queue_command_sync(iommu, &cmd, true); 3127 3123 if (ret) 3128 - goto out; 3124 + goto out_err; 3129 3125 ret = __iommu_queue_command_sync(iommu, &cmd2, false); 3130 3126 if (ret) 3131 - goto out; 3132 - wait_on_sem(iommu, data); 3133 - out: 3127 + goto out_err; 3134 3128 raw_spin_unlock_irqrestore(&iommu->lock, flags); 3129 + 3130 + wait_on_sem(iommu, data); 3131 + return; 3132 + 3133 + out_err: 3134 + raw_spin_unlock_irqrestore(&iommu->lock, flags); 3135 + return; 3135 3136 } 3136 3137 3137 3138 static inline u8 iommu_get_int_tablen(struct iommu_dev_data *dev_data)