Commit 23e967e1 authored by Tom Lendacky's avatar Tom Lendacky Committed by Joerg Roedel

iommu/amd: Reduce delay waiting for command buffer space

Currently if there is no room to add a command to the command buffer, the
driver performs a "completion wait" which only returns when all commands
on the queue have been processed. There is no need to wait for the entire
command queue to be executed before adding the next command.

Update the driver to perform the same udelay() loop that the "completion
wait" performs, but instead re-read the head pointer to determine if
sufficient space is available.  The very first time it is found that there
is no space available, the udelay() will be skipped to immediately perform
the opportunistic read of the head pointer. If it is still found that
there is not sufficient space, then the udelay() will be performed.
Signed-off-by: default avatarLeo Duran <leo.duran@amd.com>
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent d334a563
......@@ -1045,7 +1045,7 @@ static int __iommu_queue_command_sync(struct amd_iommu *iommu,
struct iommu_cmd *cmd,
bool sync)
{
bool read_head = true;
unsigned int count = 0;
u32 left, next_tail;
next_tail = (iommu->cmd_buf_tail + sizeof(*cmd)) % CMD_BUFFER_SIZE;
......@@ -1053,33 +1053,26 @@ static int __iommu_queue_command_sync(struct amd_iommu *iommu,
left = (iommu->cmd_buf_head - next_tail) % CMD_BUFFER_SIZE;
if (left <= 0x20) {
struct iommu_cmd sync_cmd;
int ret;
if (read_head) {
/* Update head and recheck remaining space */
iommu->cmd_buf_head = readl(iommu->mmio_base +
MMIO_CMD_HEAD_OFFSET);
read_head = false;
goto again;
}
read_head = true;
iommu->cmd_sem = 0;
/* Skip udelay() the first time around */
if (count++) {
if (count == LOOP_TIMEOUT) {
pr_err("AMD-Vi: Command buffer timeout\n");
return -EIO;
}
build_completion_wait(&sync_cmd, (u64)&iommu->cmd_sem);
copy_cmd_to_buffer(iommu, &sync_cmd);
udelay(1);
}
if ((ret = wait_on_sem(&iommu->cmd_sem)) != 0)
return ret;
/* Update head and recheck remaining space */
iommu->cmd_buf_head = readl(iommu->mmio_base +
MMIO_CMD_HEAD_OFFSET);
goto again;
}
copy_cmd_to_buffer(iommu, cmd);
/* We need to sync now to make sure all commands are processed */
/* Do we need to make sure all commands are processed? */
iommu->need_sync = sync;
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment