aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhen Lei <thunder.leizhen@huawei.com>2018-08-19 03:51:11 -0400
committerWill Deacon <will.deacon@arm.com>2018-10-01 08:01:30 -0400
commit901510ee32f7190902f6fe4affb463e5d86a804c (patch)
tree8dd5e201f928a66719efcf13327e6d5a746b1d5e
parent0f02477d16980938a84aba8688a4e3a303306116 (diff)
iommu/arm-smmu-v3: Avoid back-to-back CMD_SYNC operations
Putting adjacent CMD_SYNCs into the command queue is nonsensical, but can happen when multiple CPUs are inserting commands. Rather than leave the poor old hardware to chew through these operations, we can instead drop the subsequent SYNCs and poll for completion of the first. This has been shown to improve IO performance under pressure, where the number of SYNC operations reduces by about a third: CMD_SYNCs reduced: 19542181 CMD_SYNCs total: 58098548 (include reduced) CMDs total: 116197099 (TLBI:SYNC about 1:1) Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--drivers/iommu/arm-smmu-v3.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 48baffd07aef..e395f1ff3f81 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -568,6 +568,7 @@ struct arm_smmu_device {
568 int gerr_irq; 568 int gerr_irq;
569 int combined_irq; 569 int combined_irq;
570 u32 sync_nr; 570 u32 sync_nr;
571 u8 prev_cmd_opcode;
571 572
572 unsigned long ias; /* IPA */ 573 unsigned long ias; /* IPA */
573 unsigned long oas; /* PA */ 574 unsigned long oas; /* PA */
@@ -901,6 +902,8 @@ static void arm_smmu_cmdq_insert_cmd(struct arm_smmu_device *smmu, u64 *cmd)
901 struct arm_smmu_queue *q = &smmu->cmdq.q; 902 struct arm_smmu_queue *q = &smmu->cmdq.q;
902 bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV); 903 bool wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
903 904
905 smmu->prev_cmd_opcode = FIELD_GET(CMDQ_0_OP, cmd[0]);
906
904 while (queue_insert_raw(q, cmd) == -ENOSPC) { 907 while (queue_insert_raw(q, cmd) == -ENOSPC) {
905 if (queue_poll_cons(q, false, wfe)) 908 if (queue_poll_cons(q, false, wfe))
906 dev_err_ratelimited(smmu->dev, "CMDQ timeout\n"); 909 dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
@@ -953,9 +956,16 @@ static int __arm_smmu_cmdq_issue_sync_msi(struct arm_smmu_device *smmu)
953 }; 956 };
954 957
955 spin_lock_irqsave(&smmu->cmdq.lock, flags); 958 spin_lock_irqsave(&smmu->cmdq.lock, flags);
956 ent.sync.msidata = ++smmu->sync_nr; 959
957 arm_smmu_cmdq_build_cmd(cmd, &ent); 960 /* Piggy-back on the previous command if it's a SYNC */
958 arm_smmu_cmdq_insert_cmd(smmu, cmd); 961 if (smmu->prev_cmd_opcode == CMDQ_OP_CMD_SYNC) {
962 ent.sync.msidata = smmu->sync_nr;
963 } else {
964 ent.sync.msidata = ++smmu->sync_nr;
965 arm_smmu_cmdq_build_cmd(cmd, &ent);
966 arm_smmu_cmdq_insert_cmd(smmu, cmd);
967 }
968
959 spin_unlock_irqrestore(&smmu->cmdq.lock, flags); 969 spin_unlock_irqrestore(&smmu->cmdq.lock, flags);
960 970
961 return __arm_smmu_sync_poll_msi(smmu, ent.sync.msidata); 971 return __arm_smmu_sync_poll_msi(smmu, ent.sync.msidata);