Skip to content

Commit f935448

Browse files
Geetha Sowjanyawildea01
authored andcommitted
iommu/arm-smmu-v3: Add workaround for Cavium ThunderX2 erratum torvalds#126
Cavium ThunderX2 SMMU doesn't support MSI and also doesn't have unique irq lines for gerror, eventq and cmdq-sync. New named irq "combined" is set as a errata workaround, which allows to share the irq line by register single irq handler for all the interrupts. Acked-by: Lorenzo Pieralisi <[email protected]> Signed-off-by: Geetha sowjanya <[email protected]> [will: reworked irq equality checking and added SPI check] Signed-off-by: Will Deacon <[email protected]>
1 parent 99caf17 commit f935448

File tree

4 files changed

+121
-43
lines changed

4 files changed

+121
-43
lines changed

Documentation/arm64/silicon-errata.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ stable kernels.
6363
| Cavium | ThunderX Core | #27456 | CAVIUM_ERRATUM_27456 |
6464
| Cavium | ThunderX SMMUv2 | #27704 | N/A |
6565
| Cavium | ThunderX2 SMMUv3| #74 | N/A |
66+
| Cavium | ThunderX2 SMMUv3| #126 | N/A |
6667
| | | | |
6768
| Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 |
6869
| | | | |

Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ the PCIe specification.
2626
* "priq" - PRI Queue not empty
2727
* "cmdq-sync" - CMD_SYNC complete
2828
* "gerror" - Global Error activated
29+
* "combined" - The combined interrupt is optional,
30+
and should only be provided if the
31+
hardware supports just a single,
32+
combined interrupt line.
33+
If provided, then the combined interrupt
34+
will be used in preference to any others.
2935

3036
- #iommu-cells : See the generic IOMMU binding described in
3137
devicetree/bindings/pci/pci-iommu.txt

drivers/acpi/arm64/iort.c

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,24 @@ static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
833833
return num_res;
834834
}
835835

836+
static bool arm_smmu_v3_is_combined_irq(struct acpi_iort_smmu_v3 *smmu)
837+
{
838+
/*
839+
* Cavium ThunderX2 implementation doesn't not support unique
840+
* irq line. Use single irq line for all the SMMUv3 interrupts.
841+
*/
842+
if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX)
843+
return false;
844+
845+
/*
846+
* ThunderX2 doesn't support MSIs from the SMMU, so we're checking
847+
* SPI numbers here.
848+
*/
849+
return smmu->event_gsiv == smmu->pri_gsiv &&
850+
smmu->event_gsiv == smmu->gerr_gsiv &&
851+
smmu->event_gsiv == smmu->sync_gsiv;
852+
}
853+
836854
static unsigned long arm_smmu_v3_resource_size(struct acpi_iort_smmu_v3 *smmu)
837855
{
838856
/*
@@ -860,26 +878,33 @@ static void __init arm_smmu_v3_init_resources(struct resource *res,
860878
res[num_res].flags = IORESOURCE_MEM;
861879

862880
num_res++;
881+
if (arm_smmu_v3_is_combined_irq(smmu)) {
882+
if (smmu->event_gsiv)
883+
acpi_iort_register_irq(smmu->event_gsiv, "combined",
884+
ACPI_EDGE_SENSITIVE,
885+
&res[num_res++]);
886+
} else {
863887

864-
if (smmu->event_gsiv)
865-
acpi_iort_register_irq(smmu->event_gsiv, "eventq",
866-
ACPI_EDGE_SENSITIVE,
867-
&res[num_res++]);
868-
869-
if (smmu->pri_gsiv)
870-
acpi_iort_register_irq(smmu->pri_gsiv, "priq",
871-
ACPI_EDGE_SENSITIVE,
872-
&res[num_res++]);
873-
874-
if (smmu->gerr_gsiv)
875-
acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
876-
ACPI_EDGE_SENSITIVE,
877-
&res[num_res++]);
878-
879-
if (smmu->sync_gsiv)
880-
acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
881-
ACPI_EDGE_SENSITIVE,
882-
&res[num_res++]);
888+
if (smmu->event_gsiv)
889+
acpi_iort_register_irq(smmu->event_gsiv, "eventq",
890+
ACPI_EDGE_SENSITIVE,
891+
&res[num_res++]);
892+
893+
if (smmu->pri_gsiv)
894+
acpi_iort_register_irq(smmu->pri_gsiv, "priq",
895+
ACPI_EDGE_SENSITIVE,
896+
&res[num_res++]);
897+
898+
if (smmu->gerr_gsiv)
899+
acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
900+
ACPI_EDGE_SENSITIVE,
901+
&res[num_res++]);
902+
903+
if (smmu->sync_gsiv)
904+
acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
905+
ACPI_EDGE_SENSITIVE,
906+
&res[num_res++]);
907+
}
883908
}
884909

885910
static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)

drivers/iommu/arm-smmu-v3.c

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ struct arm_smmu_device {
615615
struct arm_smmu_priq priq;
616616

617617
int gerr_irq;
618+
int combined_irq;
618619

619620
unsigned long ias; /* IPA */
620621
unsigned long oas; /* PA */
@@ -1330,6 +1331,24 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
13301331
return IRQ_HANDLED;
13311332
}
13321333

1334+
static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
1335+
{
1336+
struct arm_smmu_device *smmu = dev;
1337+
1338+
arm_smmu_evtq_thread(irq, dev);
1339+
if (smmu->features & ARM_SMMU_FEAT_PRI)
1340+
arm_smmu_priq_thread(irq, dev);
1341+
1342+
return IRQ_HANDLED;
1343+
}
1344+
1345+
static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
1346+
{
1347+
arm_smmu_gerror_handler(irq, dev);
1348+
arm_smmu_cmdq_sync_handler(irq, dev);
1349+
return IRQ_WAKE_THREAD;
1350+
}
1351+
13331352
/* IO_PGTABLE API */
13341353
static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
13351354
{
@@ -2229,18 +2248,9 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
22292248
devm_add_action(dev, arm_smmu_free_msis, dev);
22302249
}
22312250

2232-
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
2251+
static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
22332252
{
2234-
int ret, irq;
2235-
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
2236-
2237-
/* Disable IRQs first */
2238-
ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
2239-
ARM_SMMU_IRQ_CTRLACK);
2240-
if (ret) {
2241-
dev_err(smmu->dev, "failed to disable irqs\n");
2242-
return ret;
2243-
}
2253+
int irq, ret;
22442254

22452255
arm_smmu_setup_msis(smmu);
22462256

@@ -2283,10 +2293,41 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
22832293
if (ret < 0)
22842294
dev_warn(smmu->dev,
22852295
"failed to enable priq irq\n");
2286-
else
2287-
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
22882296
}
22892297
}
2298+
}
2299+
2300+
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
2301+
{
2302+
int ret, irq;
2303+
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
2304+
2305+
/* Disable IRQs first */
2306+
ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
2307+
ARM_SMMU_IRQ_CTRLACK);
2308+
if (ret) {
2309+
dev_err(smmu->dev, "failed to disable irqs\n");
2310+
return ret;
2311+
}
2312+
2313+
irq = smmu->combined_irq;
2314+
if (irq) {
2315+
/*
2316+
* Cavium ThunderX2 implementation doesn't not support unique
2317+
* irq lines. Use single irq line for all the SMMUv3 interrupts.
2318+
*/
2319+
ret = devm_request_threaded_irq(smmu->dev, irq,
2320+
arm_smmu_combined_irq_handler,
2321+
arm_smmu_combined_irq_thread,
2322+
IRQF_ONESHOT,
2323+
"arm-smmu-v3-combined-irq", smmu);
2324+
if (ret < 0)
2325+
dev_warn(smmu->dev, "failed to enable combined irq\n");
2326+
} else
2327+
arm_smmu_setup_unique_irqs(smmu);
2328+
2329+
if (smmu->features & ARM_SMMU_FEAT_PRI)
2330+
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
22902331

22912332
/* Enable interrupt generation on the SMMU */
22922333
ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
@@ -2729,22 +2770,27 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
27292770
return PTR_ERR(smmu->base);
27302771

27312772
/* Interrupt lines */
2732-
irq = platform_get_irq_byname(pdev, "eventq");
2733-
if (irq > 0)
2734-
smmu->evtq.q.irq = irq;
27352773

2736-
irq = platform_get_irq_byname(pdev, "priq");
2774+
irq = platform_get_irq_byname(pdev, "combined");
27372775
if (irq > 0)
2738-
smmu->priq.q.irq = irq;
2776+
smmu->combined_irq = irq;
2777+
else {
2778+
irq = platform_get_irq_byname(pdev, "eventq");
2779+
if (irq > 0)
2780+
smmu->evtq.q.irq = irq;
27392781

2740-
irq = platform_get_irq_byname(pdev, "cmdq-sync");
2741-
if (irq > 0)
2742-
smmu->cmdq.q.irq = irq;
2782+
irq = platform_get_irq_byname(pdev, "priq");
2783+
if (irq > 0)
2784+
smmu->priq.q.irq = irq;
27432785

2744-
irq = platform_get_irq_byname(pdev, "gerror");
2745-
if (irq > 0)
2746-
smmu->gerr_irq = irq;
2786+
irq = platform_get_irq_byname(pdev, "cmdq-sync");
2787+
if (irq > 0)
2788+
smmu->cmdq.q.irq = irq;
27472789

2790+
irq = platform_get_irq_byname(pdev, "gerror");
2791+
if (irq > 0)
2792+
smmu->gerr_irq = irq;
2793+
}
27482794
/* Probe the h/w */
27492795
ret = arm_smmu_device_hw_probe(smmu);
27502796
if (ret)

0 commit comments

Comments
 (0)