aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Lendacky <thomas.lendacky@amd.com>2017-06-05 15:52:26 -0400
committerJoerg Roedel <jroedel@suse.de>2017-06-08 08:31:03 -0400
commit23e967e17c58779b38f69f8d41d727f59440d36a (patch)
tree32d99307e8bef0fcf0d7230382637303bd28cc40
parentd334a5637dfb53f7d07017afc1e491903b482ef8 (diff)
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: Leo Duran <leo.duran@amd.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/amd_iommu.c33
1 files changed, 13 insertions, 20 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index d81c895ff4f4..1efbef7f3b61 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -1045,7 +1045,7 @@ static int __iommu_queue_command_sync(struct amd_iommu *iommu,
1045 struct iommu_cmd *cmd, 1045 struct iommu_cmd *cmd,
1046 bool sync) 1046 bool sync)
1047{ 1047{
1048 bool read_head = true; 1048 unsigned int count = 0;
1049 u32 left, next_tail; 1049 u32 left, next_tail;
1050 1050
1051 next_tail = (iommu->cmd_buf_tail + sizeof(*cmd)) % CMD_BUFFER_SIZE; 1051 next_tail = (iommu->cmd_buf_tail + sizeof(*cmd)) % CMD_BUFFER_SIZE;
@@ -1053,33 +1053,26 @@ again:
1053 left = (iommu->cmd_buf_head - next_tail) % CMD_BUFFER_SIZE; 1053 left = (iommu->cmd_buf_head - next_tail) % CMD_BUFFER_SIZE;
1054 1054
1055 if (left <= 0x20) { 1055 if (left <= 0x20) {
1056 struct iommu_cmd sync_cmd; 1056 /* Skip udelay() the first time around */
1057 int ret; 1057 if (count++) {
1058 1058 if (count == LOOP_TIMEOUT) {
1059 if (read_head) { 1059 pr_err("AMD-Vi: Command buffer timeout\n");
1060 /* Update head and recheck remaining space */ 1060 return -EIO;
1061 iommu->cmd_buf_head = readl(iommu->mmio_base + 1061 }
1062 MMIO_CMD_HEAD_OFFSET);
1063 read_head = false;
1064 goto again;
1065 }
1066
1067 read_head = true;
1068
1069 iommu->cmd_sem = 0;
1070 1062
1071 build_completion_wait(&sync_cmd, (u64)&iommu->cmd_sem); 1063 udelay(1);
1072 copy_cmd_to_buffer(iommu, &sync_cmd); 1064 }
1073 1065
1074 if ((ret = wait_on_sem(&iommu->cmd_sem)) != 0) 1066 /* Update head and recheck remaining space */
1075 return ret; 1067 iommu->cmd_buf_head = readl(iommu->mmio_base +
1068 MMIO_CMD_HEAD_OFFSET);
1076 1069
1077 goto again; 1070 goto again;
1078 } 1071 }
1079 1072
1080 copy_cmd_to_buffer(iommu, cmd); 1073 copy_cmd_to_buffer(iommu, cmd);
1081 1074
1082 /* We need to sync now to make sure all commands are processed */ 1075 /* Do we need to make sure all commands are processed? */
1083 iommu->need_sync = sync; 1076 iommu->need_sync = sync;
1084 1077
1085 return 0; 1078 return 0;