diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-26 23:12:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-26 23:12:35 -0400 |
commit | 67a8c7d636886ee05cc139833b8f1aef0e685c2c (patch) | |
tree | 27b931132dc06b681170c32d6e41ea46a181d073 | |
parent | fd1ae514528bfa7136640301523f646f396134e2 (diff) | |
parent | 4df36185bb364f9727d1c0816acac3b9a5ae2603 (diff) |
Merge tag 'iommu-fixes-v4.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU fixes from Joerg Roedel:
"Fixes from Will Deacon:
- fix a couple of thinkos in the CMDQ error handling and
short-descriptor page table code that have been there since day one
- disable stalling faults, since they may result in hardware deadlock
- fix an accidental BUG() when passing disable_bypass=1 on the
cmdline"
* tag 'iommu-fixes-v4.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
iommu/arm-smmu: Don't BUG() if we find aborting STEs with disable_bypass
iommu/arm-smmu: Disable stalling faults for all endpoints
iommu/arm-smmu: Fix CMDQ error handling
iommu/io-pgtable-arm-v7s: Fix attributes when splitting blocks
-rw-r--r-- | drivers/iommu/arm-smmu-v3.c | 7 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu.c | 34 | ||||
-rw-r--r-- | drivers/iommu/io-pgtable-arm-v7s.c | 4 |
3 files changed, 15 insertions, 30 deletions
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index ce801170d5f2..641e88761319 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c | |||
@@ -879,7 +879,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu) | |||
879 | * We may have concurrent producers, so we need to be careful | 879 | * We may have concurrent producers, so we need to be careful |
880 | * not to touch any of the shadow cmdq state. | 880 | * not to touch any of the shadow cmdq state. |
881 | */ | 881 | */ |
882 | queue_read(cmd, Q_ENT(q, idx), q->ent_dwords); | 882 | queue_read(cmd, Q_ENT(q, cons), q->ent_dwords); |
883 | dev_err(smmu->dev, "skipping command in error state:\n"); | 883 | dev_err(smmu->dev, "skipping command in error state:\n"); |
884 | for (i = 0; i < ARRAY_SIZE(cmd); ++i) | 884 | for (i = 0; i < ARRAY_SIZE(cmd); ++i) |
885 | dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]); | 885 | dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]); |
@@ -890,7 +890,7 @@ static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu) | |||
890 | return; | 890 | return; |
891 | } | 891 | } |
892 | 892 | ||
893 | queue_write(cmd, Q_ENT(q, idx), q->ent_dwords); | 893 | queue_write(Q_ENT(q, cons), cmd, q->ent_dwords); |
894 | } | 894 | } |
895 | 895 | ||
896 | static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu, | 896 | static void arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu, |
@@ -1034,6 +1034,9 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, | |||
1034 | case STRTAB_STE_0_CFG_S2_TRANS: | 1034 | case STRTAB_STE_0_CFG_S2_TRANS: |
1035 | ste_live = true; | 1035 | ste_live = true; |
1036 | break; | 1036 | break; |
1037 | case STRTAB_STE_0_CFG_ABORT: | ||
1038 | if (disable_bypass) | ||
1039 | break; | ||
1037 | default: | 1040 | default: |
1038 | BUG(); /* STE corruption */ | 1041 | BUG(); /* STE corruption */ |
1039 | } | 1042 | } |
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4f49fe29f202..2db74ebc3240 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
@@ -686,8 +686,7 @@ static struct iommu_gather_ops arm_smmu_gather_ops = { | |||
686 | 686 | ||
687 | static irqreturn_t arm_smmu_context_fault(int irq, void *dev) | 687 | static irqreturn_t arm_smmu_context_fault(int irq, void *dev) |
688 | { | 688 | { |
689 | int flags, ret; | 689 | u32 fsr, fsynr; |
690 | u32 fsr, fsynr, resume; | ||
691 | unsigned long iova; | 690 | unsigned long iova; |
692 | struct iommu_domain *domain = dev; | 691 | struct iommu_domain *domain = dev; |
693 | struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); | 692 | struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); |
@@ -701,34 +700,15 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) | |||
701 | if (!(fsr & FSR_FAULT)) | 700 | if (!(fsr & FSR_FAULT)) |
702 | return IRQ_NONE; | 701 | return IRQ_NONE; |
703 | 702 | ||
704 | if (fsr & FSR_IGN) | ||
705 | dev_err_ratelimited(smmu->dev, | ||
706 | "Unexpected context fault (fsr 0x%x)\n", | ||
707 | fsr); | ||
708 | |||
709 | fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0); | 703 | fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0); |
710 | flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ; | ||
711 | |||
712 | iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR); | 704 | iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR); |
713 | if (!report_iommu_fault(domain, smmu->dev, iova, flags)) { | ||
714 | ret = IRQ_HANDLED; | ||
715 | resume = RESUME_RETRY; | ||
716 | } else { | ||
717 | dev_err_ratelimited(smmu->dev, | ||
718 | "Unhandled context fault: iova=0x%08lx, fsynr=0x%x, cb=%d\n", | ||
719 | iova, fsynr, cfg->cbndx); | ||
720 | ret = IRQ_NONE; | ||
721 | resume = RESUME_TERMINATE; | ||
722 | } | ||
723 | |||
724 | /* Clear the faulting FSR */ | ||
725 | writel(fsr, cb_base + ARM_SMMU_CB_FSR); | ||
726 | 705 | ||
727 | /* Retry or terminate any stalled transactions */ | 706 | dev_err_ratelimited(smmu->dev, |
728 | if (fsr & FSR_SS) | 707 | "Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cb=%d\n", |
729 | writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME); | 708 | fsr, iova, fsynr, cfg->cbndx); |
730 | 709 | ||
731 | return ret; | 710 | writel(fsr, cb_base + ARM_SMMU_CB_FSR); |
711 | return IRQ_HANDLED; | ||
732 | } | 712 | } |
733 | 713 | ||
734 | static irqreturn_t arm_smmu_global_fault(int irq, void *dev) | 714 | static irqreturn_t arm_smmu_global_fault(int irq, void *dev) |
@@ -837,7 +817,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, | |||
837 | } | 817 | } |
838 | 818 | ||
839 | /* SCTLR */ | 819 | /* SCTLR */ |
840 | reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP; | 820 | reg = SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP; |
841 | if (stage1) | 821 | if (stage1) |
842 | reg |= SCTLR_S1_ASIDPNE; | 822 | reg |= SCTLR_S1_ASIDPNE; |
843 | #ifdef __BIG_ENDIAN | 823 | #ifdef __BIG_ENDIAN |
diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 8c6139986d7d..def8ca1c982d 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c | |||
@@ -286,12 +286,14 @@ static int arm_v7s_pte_to_prot(arm_v7s_iopte pte, int lvl) | |||
286 | int prot = IOMMU_READ; | 286 | int prot = IOMMU_READ; |
287 | arm_v7s_iopte attr = pte >> ARM_V7S_ATTR_SHIFT(lvl); | 287 | arm_v7s_iopte attr = pte >> ARM_V7S_ATTR_SHIFT(lvl); |
288 | 288 | ||
289 | if (attr & ARM_V7S_PTE_AP_RDONLY) | 289 | if (!(attr & ARM_V7S_PTE_AP_RDONLY)) |
290 | prot |= IOMMU_WRITE; | 290 | prot |= IOMMU_WRITE; |
291 | if ((attr & (ARM_V7S_TEX_MASK << ARM_V7S_TEX_SHIFT)) == 0) | 291 | if ((attr & (ARM_V7S_TEX_MASK << ARM_V7S_TEX_SHIFT)) == 0) |
292 | prot |= IOMMU_MMIO; | 292 | prot |= IOMMU_MMIO; |
293 | else if (pte & ARM_V7S_ATTR_C) | 293 | else if (pte & ARM_V7S_ATTR_C) |
294 | prot |= IOMMU_CACHE; | 294 | prot |= IOMMU_CACHE; |
295 | if (pte & ARM_V7S_ATTR_XN(lvl)) | ||
296 | prot |= IOMMU_NOEXEC; | ||
295 | 297 | ||
296 | return prot; | 298 | return prot; |
297 | } | 299 | } |