Skip to content

Commit 28611d5

Browse files
Geetha Sowjanyajchandra-cavm
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]> (commit f935448 joro-iommu)
1 parent 0452a87 commit 28611d5

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
@@ -62,6 +62,7 @@ stable kernels.
6262
| Cavium | ThunderX Core | #27456 | CAVIUM_ERRATUM_27456 |
6363
| Cavium | ThunderX SMMUv2 | #27704 | N/A |
6464
| Cavium | ThunderX2 SMMUv3| #74 | N/A |
65+
| Cavium | ThunderX2 SMMUv3| #126 | N/A |
6566
| | | | |
6667
| Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 |
6768
| | | | |

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
@@ -669,6 +669,24 @@ static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
669669
return num_res;
670670
}
671671

672+
static bool arm_smmu_v3_is_combined_irq(struct acpi_iort_smmu_v3 *smmu)
673+
{
674+
/*
675+
* Cavium ThunderX2 implementation doesn't not support unique
676+
* irq line. Use single irq line for all the SMMUv3 interrupts.
677+
*/
678+
if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX)
679+
return false;
680+
681+
/*
682+
* ThunderX2 doesn't support MSIs from the SMMU, so we're checking
683+
* SPI numbers here.
684+
*/
685+
return smmu->event_gsiv == smmu->pri_gsiv &&
686+
smmu->event_gsiv == smmu->gerr_gsiv &&
687+
smmu->event_gsiv == smmu->sync_gsiv;
688+
}
689+
672690
static unsigned long arm_smmu_v3_resource_size(struct acpi_iort_smmu_v3 *smmu)
673691
{
674692
/*
@@ -696,26 +714,33 @@ static void __init arm_smmu_v3_init_resources(struct resource *res,
696714
res[num_res].flags = IORESOURCE_MEM;
697715

698716
num_res++;
717+
if (arm_smmu_v3_is_combined_irq(smmu)) {
718+
if (smmu->event_gsiv)
719+
acpi_iort_register_irq(smmu->event_gsiv, "combined",
720+
ACPI_EDGE_SENSITIVE,
721+
&res[num_res++]);
722+
} else {
699723

700-
if (smmu->event_gsiv)
701-
acpi_iort_register_irq(smmu->event_gsiv, "eventq",
702-
ACPI_EDGE_SENSITIVE,
703-
&res[num_res++]);
704-
705-
if (smmu->pri_gsiv)
706-
acpi_iort_register_irq(smmu->pri_gsiv, "priq",
707-
ACPI_EDGE_SENSITIVE,
708-
&res[num_res++]);
709-
710-
if (smmu->gerr_gsiv)
711-
acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
712-
ACPI_EDGE_SENSITIVE,
713-
&res[num_res++]);
714-
715-
if (smmu->sync_gsiv)
716-
acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
717-
ACPI_EDGE_SENSITIVE,
718-
&res[num_res++]);
724+
if (smmu->event_gsiv)
725+
acpi_iort_register_irq(smmu->event_gsiv, "eventq",
726+
ACPI_EDGE_SENSITIVE,
727+
&res[num_res++]);
728+
729+
if (smmu->pri_gsiv)
730+
acpi_iort_register_irq(smmu->pri_gsiv, "priq",
731+
ACPI_EDGE_SENSITIVE,
732+
&res[num_res++]);
733+
734+
if (smmu->gerr_gsiv)
735+
acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
736+
ACPI_EDGE_SENSITIVE,
737+
&res[num_res++]);
738+
739+
if (smmu->sync_gsiv)
740+
acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
741+
ACPI_EDGE_SENSITIVE,
742+
&res[num_res++]);
743+
}
719744
}
720745

721746
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
@@ -606,6 +606,7 @@ struct arm_smmu_device {
606606
struct arm_smmu_priq priq;
607607

608608
int gerr_irq;
609+
int combined_irq;
609610

610611
unsigned long ias; /* IPA */
611612
unsigned long oas; /* PA */
@@ -1320,6 +1321,24 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
13201321
return IRQ_HANDLED;
13211322
}
13221323

1324+
static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
1325+
{
1326+
struct arm_smmu_device *smmu = dev;
1327+
1328+
arm_smmu_evtq_thread(irq, dev);
1329+
if (smmu->features & ARM_SMMU_FEAT_PRI)
1330+
arm_smmu_priq_thread(irq, dev);
1331+
1332+
return IRQ_HANDLED;
1333+
}
1334+
1335+
static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
1336+
{
1337+
arm_smmu_gerror_handler(irq, dev);
1338+
arm_smmu_cmdq_sync_handler(irq, dev);
1339+
return IRQ_WAKE_THREAD;
1340+
}
1341+
13231342
/* IO_PGTABLE API */
13241343
static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
13251344
{
@@ -2222,18 +2241,9 @@ static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
22222241
devm_add_action(dev, arm_smmu_free_msis, dev);
22232242
}
22242243

2225-
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
2244+
static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
22262245
{
2227-
int ret, irq;
2228-
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
2229-
2230-
/* Disable IRQs first */
2231-
ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
2232-
ARM_SMMU_IRQ_CTRLACK);
2233-
if (ret) {
2234-
dev_err(smmu->dev, "failed to disable irqs\n");
2235-
return ret;
2236-
}
2246+
int irq, ret;
22372247

22382248
arm_smmu_setup_msis(smmu);
22392249

@@ -2276,10 +2286,41 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
22762286
if (ret < 0)
22772287
dev_warn(smmu->dev,
22782288
"failed to enable priq irq\n");
2279-
else
2280-
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
22812289
}
22822290
}
2291+
}
2292+
2293+
static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
2294+
{
2295+
int ret, irq;
2296+
u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
2297+
2298+
/* Disable IRQs first */
2299+
ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
2300+
ARM_SMMU_IRQ_CTRLACK);
2301+
if (ret) {
2302+
dev_err(smmu->dev, "failed to disable irqs\n");
2303+
return ret;
2304+
}
2305+
2306+
irq = smmu->combined_irq;
2307+
if (irq) {
2308+
/*
2309+
* Cavium ThunderX2 implementation doesn't not support unique
2310+
* irq lines. Use single irq line for all the SMMUv3 interrupts.
2311+
*/
2312+
ret = devm_request_threaded_irq(smmu->dev, irq,
2313+
arm_smmu_combined_irq_handler,
2314+
arm_smmu_combined_irq_thread,
2315+
IRQF_ONESHOT,
2316+
"arm-smmu-v3-combined-irq", smmu);
2317+
if (ret < 0)
2318+
dev_warn(smmu->dev, "failed to enable combined irq\n");
2319+
} else
2320+
arm_smmu_setup_unique_irqs(smmu);
2321+
2322+
if (smmu->features & ARM_SMMU_FEAT_PRI)
2323+
irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
22832324

22842325
/* Enable interrupt generation on the SMMU */
22852326
ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
@@ -2716,22 +2757,27 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
27162757
return PTR_ERR(smmu->base);
27172758

27182759
/* Interrupt lines */
2719-
irq = platform_get_irq_byname(pdev, "eventq");
2720-
if (irq > 0)
2721-
smmu->evtq.q.irq = irq;
27222760

2723-
irq = platform_get_irq_byname(pdev, "priq");
2761+
irq = platform_get_irq_byname(pdev, "combined");
27242762
if (irq > 0)
2725-
smmu->priq.q.irq = irq;
2763+
smmu->combined_irq = irq;
2764+
else {
2765+
irq = platform_get_irq_byname(pdev, "eventq");
2766+
if (irq > 0)
2767+
smmu->evtq.q.irq = irq;
27262768

2727-
irq = platform_get_irq_byname(pdev, "cmdq-sync");
2728-
if (irq > 0)
2729-
smmu->cmdq.q.irq = irq;
2769+
irq = platform_get_irq_byname(pdev, "priq");
2770+
if (irq > 0)
2771+
smmu->priq.q.irq = irq;
27302772

2731-
irq = platform_get_irq_byname(pdev, "gerror");
2732-
if (irq > 0)
2733-
smmu->gerr_irq = irq;
2773+
irq = platform_get_irq_byname(pdev, "cmdq-sync");
2774+
if (irq > 0)
2775+
smmu->cmdq.q.irq = irq;
27342776

2777+
irq = platform_get_irq_byname(pdev, "gerror");
2778+
if (irq > 0)
2779+
smmu->gerr_irq = irq;
2780+
}
27352781
/* Probe the h/w */
27362782
ret = arm_smmu_device_hw_probe(smmu);
27372783
if (ret)

0 commit comments

Comments
 (0)