Skip to content
/ linux Public

Commit e15768e

Browse files
Ankit SoniSasha Levin
authored andcommitted
iommu/amd: move wait_on_sem() out of spinlock
[ Upstream commit d2a0cac ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 3308c75 commit e15768e

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

drivers/iommu/amd/iommu.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,12 @@ static int wait_on_sem(struct amd_iommu *iommu, u64 data)
11561156
{
11571157
int i = 0;
11581158

1159-
while (*iommu->cmd_sem != data && i < LOOP_TIMEOUT) {
1159+
/*
1160+
* cmd_sem holds a monotonically non-decreasing completion sequence
1161+
* number.
1162+
*/
1163+
while ((__s64)(READ_ONCE(*iommu->cmd_sem) - data) < 0 &&
1164+
i < LOOP_TIMEOUT) {
11601165
udelay(1);
11611166
i += 1;
11621167
}
@@ -1401,14 +1406,13 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
14011406
raw_spin_lock_irqsave(&iommu->lock, flags);
14021407

14031408
ret = __iommu_queue_command_sync(iommu, &cmd, false);
1409+
raw_spin_unlock_irqrestore(&iommu->lock, flags);
1410+
14041411
if (ret)
1405-
goto out_unlock;
1412+
return ret;
14061413

14071414
ret = wait_on_sem(iommu, data);
14081415

1409-
out_unlock:
1410-
raw_spin_unlock_irqrestore(&iommu->lock, flags);
1411-
14121416
return ret;
14131417
}
14141418

@@ -3088,13 +3092,18 @@ static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid)
30883092
raw_spin_lock_irqsave(&iommu->lock, flags);
30893093
ret = __iommu_queue_command_sync(iommu, &cmd, true);
30903094
if (ret)
3091-
goto out;
3095+
goto out_err;
30923096
ret = __iommu_queue_command_sync(iommu, &cmd2, false);
30933097
if (ret)
3094-
goto out;
3098+
goto out_err;
3099+
raw_spin_unlock_irqrestore(&iommu->lock, flags);
3100+
30953101
wait_on_sem(iommu, data);
3096-
out:
3102+
return;
3103+
3104+
out_err:
30973105
raw_spin_unlock_irqrestore(&iommu->lock, flags);
3106+
return;
30983107
}
30993108

31003109
static inline u8 iommu_get_int_tablen(struct iommu_dev_data *dev_data)

0 commit comments

Comments
 (0)