Skip to content

Commit ac0ea6e

Browse files
committed
x86/amd-iommu: Improve handling of full command buffer
This patch improved the handling of commands when the IOMMU command buffer is nearly full. In this case it issues an completion wait command and waits until the IOMMU has processed it before continuing queuing new commands. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent 17b124b commit ac0ea6e

File tree

1 file changed

+65
-23
lines changed

1 file changed

+65
-23
lines changed

arch/x86/kernel/amd_iommu.c

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,39 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
381381
*
382382
****************************************************************************/
383383

384+
static int wait_on_sem(volatile u64 *sem)
385+
{
386+
int i = 0;
387+
388+
while (*sem == 0 && i < LOOP_TIMEOUT) {
389+
udelay(1);
390+
i += 1;
391+
}
392+
393+
if (i == LOOP_TIMEOUT) {
394+
pr_alert("AMD-Vi: Completion-Wait loop timed out\n");
395+
return -EIO;
396+
}
397+
398+
return 0;
399+
}
400+
401+
static void copy_cmd_to_buffer(struct amd_iommu *iommu,
402+
struct iommu_cmd *cmd,
403+
u32 tail)
404+
{
405+
u8 *target;
406+
407+
target = iommu->cmd_buf + tail;
408+
tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
409+
410+
/* Copy command to buffer */
411+
memcpy(target, cmd, sizeof(*cmd));
412+
413+
/* Tell the IOMMU about it */
414+
writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
415+
}
416+
384417
static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
385418
{
386419
WARN_ON(address & 0x7ULL);
@@ -432,25 +465,44 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
432465

433466
/*
434467
* Writes the command to the IOMMUs command buffer and informs the
435-
* hardware about the new command. Must be called with iommu->lock held.
468+
* hardware about the new command.
436469
*/
437470
static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
438471
{
472+
u32 left, tail, head, next_tail;
439473
unsigned long flags;
440-
u32 tail, head;
441-
u8 *target;
442474

443475
WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
476+
477+
again:
444478
spin_lock_irqsave(&iommu->lock, flags);
445-
tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
446-
target = iommu->cmd_buf + tail;
447-
memcpy_toio(target, cmd, sizeof(*cmd));
448-
tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
449-
head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
450-
if (tail == head)
451-
return -ENOMEM;
452-
writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
479+
480+
head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
481+
tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
482+
next_tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
483+
left = (head - next_tail) % iommu->cmd_buf_size;
484+
485+
if (left <= 2) {
486+
struct iommu_cmd sync_cmd;
487+
volatile u64 sem = 0;
488+
int ret;
489+
490+
build_completion_wait(&sync_cmd, (u64)&sem);
491+
copy_cmd_to_buffer(iommu, &sync_cmd, tail);
492+
493+
spin_unlock_irqrestore(&iommu->lock, flags);
494+
495+
if ((ret = wait_on_sem(&sem)) != 0)
496+
return ret;
497+
498+
goto again;
499+
}
500+
501+
copy_cmd_to_buffer(iommu, cmd, tail);
502+
503+
/* We need to sync now to make sure all commands are processed */
453504
iommu->need_sync = true;
505+
454506
spin_unlock_irqrestore(&iommu->lock, flags);
455507

456508
return 0;
@@ -464,7 +516,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
464516
{
465517
struct iommu_cmd cmd;
466518
volatile u64 sem = 0;
467-
int ret, i = 0;
519+
int ret;
468520

469521
if (!iommu->need_sync)
470522
return 0;
@@ -475,17 +527,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
475527
if (ret)
476528
return ret;
477529

478-
while (sem == 0 && i < LOOP_TIMEOUT) {
479-
udelay(1);
480-
i += 1;
481-
}
482-
483-
if (i == LOOP_TIMEOUT) {
484-
pr_alert("AMD-Vi: Completion-Wait loop timed out\n");
485-
ret = -EIO;
486-
}
487-
488-
return 0;
530+
return wait_on_sem(&sem);
489531
}
490532

491533
/*

0 commit comments

Comments
 (0)