From e880cd24a7a0123c1f555fe51fa6d17c89599d75 Mon Sep 17 00:00:00 2001 From: Liming Wu Date: Thu, 19 Oct 2023 19:23:18 +0800 Subject: [PATCH] anolis: iommu/arm-smmu-v3: Support JarguarMicro Corsica SMMU ANBZ: #7785 Since JaguarMicro's Corsica has some custom registers and only support combined interrupt.this patch is to be compatible with it. Signed-off-by: Liming Wu Signed-off-by: Yuxue Liu Reviewed-by: Anqing Chen --- drivers/acpi/arm64/iort.c | 11 +-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 90 +++++++++++++++++++-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 13 +++ include/acpi/actbl2.h | 1 + 4 files changed, 103 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index cad1525c34fc..c1f474a9cf49 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -1241,15 +1241,16 @@ static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node) static bool arm_smmu_v3_is_combined_irq(struct acpi_iort_smmu_v3 *smmu) { /* - * Cavium ThunderX2 implementation doesn't not support unique - * irq line. Use single irq line for all the SMMUv3 interrupts. + * Cavium ThunderX2 and JMND Corsica implementation doesn't not support + * unique irq line. Use single irq line for all the SMMUv3 interrupts. */ - if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX) + if (smmu->model != ACPI_IORT_SMMU_V3_CAVIUM_CN99XX && + smmu->model != ACPI_IORT_SMMU_V3_JMND_CORSICA) return false; /* - * ThunderX2 doesn't support MSIs from the SMMU, so we're checking - * SPI numbers here. + * ThunderX2 and JMND Corsica doesn't support MSIs from the SMMU, + * so we're checking SPI numbers here. */ return smmu->event_gsiv == smmu->pri_gsiv && smmu->event_gsiv == smmu->gerr_gsiv && diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index bee3746e5cb3..2c7529a7352c 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1574,6 +1574,46 @@ static int arm_smmu_init_event_polling(struct arm_smmu_device *smmu) } #endif +static void +arm_smmu_csr_interrupt_status_ack(struct arm_smmu_device *smmu, u32 val, + unsigned int reg_off) +{ + u32 reg; + + reg = FIELD_PREP(JMND_CORSICA_SMMU_CSR_INTERRUPT_EN_BIT, val); + writel_relaxed(reg, smmu->csr + reg_off); +} + +static irqreturn_t arm_smmu_combined_jmnd_irq_handler(int irq, void *dev) +{ + struct arm_smmu_device *smmu = dev; + u32 status, status_mask; + + status = readl_relaxed(smmu->csr + + JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_STATUS); + status_mask = status & JMND_CORSICA_SMMU_CSR_INTERRUPT_MASK; + + if (!status_mask) + return IRQ_NONE; + + if (status & JMND_CORSICA_SMMU_CSR_INTERRUPT_GERROR_MASk) { + arm_smmu_gerror_handler(irq, dev); + return IRQ_WAKE_THREAD; + } + + if (status & JMND_CORSICA_SMMU_CSR_INTERRUPT_EVENT_MASk) { + arm_smmu_evtq_thread(irq, dev); + + if (smmu->features & ARM_SMMU_FEAT_PRI) + arm_smmu_priq_thread(irq, dev); + } + + arm_smmu_csr_interrupt_status_ack(smmu, JMND_CORSICA_SMMU_CSR_INTERRUPT_MASK, + JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_CLEAR); + + return IRQ_HANDLED; +} + static void arm_smmu_atc_inv_to_cmd(int ssid, unsigned long iova, size_t size, struct arm_smmu_cmdq_ent *cmd) @@ -3270,14 +3310,23 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) irq = smmu->combined_irq; if (irq) { /* - * Cavium ThunderX2 implementation doesn't support unique irq - * lines. Use a single irq line for all the SMMUv3 interrupts. + * Cavium ThunderX2 and JMND Corsica implementation doesn't support + * unique irq lines. Use a single irq line for all the SMMUv3 + * interrupts. */ - ret = devm_request_threaded_irq(smmu->dev, irq, - arm_smmu_combined_irq_handler, - arm_smmu_combined_irq_thread, - IRQF_ONESHOT, - "arm-smmu-v3-combined-irq", smmu); + if ((smmu->options & ARM_SMMU_OPT_CUSTOM_CSR) + && (smmu->csr != NULL)) + ret = devm_request_threaded_irq(smmu->dev, irq, + arm_smmu_combined_jmnd_irq_handler, + NULL, + IRQF_ONESHOT, + "arm-smmu-v3-jmnd-irq", smmu); + else + ret = devm_request_threaded_irq(smmu->dev, irq, + arm_smmu_combined_irq_handler, + arm_smmu_combined_irq_thread, + IRQF_ONESHOT, + "arm-smmu-v3-combined-irq", smmu); if (ret < 0) dev_warn(smmu->dev, "failed to enable combined irq\n"); } else @@ -3420,6 +3469,22 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) return ret; } + if ((smmu->options & ARM_SMMU_OPT_CUSTOM_CSR) && (smmu->csr != NULL)) { + writel_relaxed(0x0, + smmu->csr + JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_EN); + reg = FIELD_PREP(JMND_CORSICA_SMMU_CSR_INTERRUPT_EN_BIT, + JMND_CORSICA_SMMU_CSR_INTERRUPT_MASK); + writel_relaxed(reg, + smmu->csr + JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_EN); + reg = readl_relaxed(smmu->csr + + JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_EN); + if (!(reg & JMND_CORSICA_SMMU_CSR_INTERRUPT_MASK)) { + dev_err(smmu->dev, + "SMMU CSR interrupt_cluster failed\n"); + return -1; + } + } + if (is_kdump_kernel()) enables &= ~(CR0_EVTQEN | CR0_PRIQEN); @@ -3699,6 +3764,9 @@ static void acpi_smmu_get_options(u32 model, struct arm_smmu_device *smmu) case ACPI_IORT_SMMU_V3_HISILICON_HI161X: smmu->options |= ARM_SMMU_OPT_SKIP_PREFETCH; break; + case ACPI_IORT_SMMU_V3_JMND_CORSICA: + smmu->options |= ARM_SMMU_OPT_CUSTOM_CSR; + break; } dev_notice(smmu->dev, "option mask 0x%x\n", smmu->options); @@ -3868,6 +3936,14 @@ static int arm_smmu_device_probe(struct platform_device *pdev) ARM_SMMU_REG_SZ); if (IS_ERR(smmu->page1)) return PTR_ERR(smmu->page1); + if (smmu->options & ARM_SMMU_OPT_CUSTOM_CSR) { + smmu->csr = arm_smmu_ioremap(dev, + ioaddr + SZ_1M - SZ_64K, SZ_64K); + if (IS_ERR(smmu->csr)) { + dev_warn(dev, "CSR io remap failed\n"); + return PTR_ERR(smmu->csr); + } + } } else { smmu->page1 = smmu->base; } diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index a6361e1da7b1..e3d32f9f8133 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -410,6 +410,15 @@ enum pri_resp { PRI_RESP_SUCC = 2, }; +/* JMND Corsica smmu custom registers */ +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_CLEAR 0x0404 +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_EN 0x0408 +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_CLUSTER_STATUS 0x0410 +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_EN_BIT GENMASK(31, 0) +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_MASK 0x4400 +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_GERROR_MASk 0x400 +#define JMND_CORSICA_SMMU_CSR_INTERRUPT_EVENT_MASk 0x4000 + struct arm_smmu_cmdq_ent { /* Common fields */ u8 opcode; @@ -623,6 +632,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) #define ARM_SMMU_OPT_PAGE0_REGS_ONLY (1 << 1) #define ARM_SMMU_OPT_MSIPOLL (1 << 2) +#define ARM_SMMU_OPT_CUSTOM_CSR (1 << 3) u32 options; struct arm_smmu_cmdq cmdq; @@ -650,6 +660,9 @@ struct arm_smmu_device { /* IOMMU core code handle */ struct iommu_device iommu; + + /* for JMND Corsica custom register */ + void __iomem *csr; #ifdef CONFIG_ARM_SMMU_V3_POLLING_EVT struct task_struct *evt_polling; #endif diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 2d3fe66c3174..9057b0033a25 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -230,6 +230,7 @@ struct acpi_iort_smmu_v3 { #define ACPI_IORT_SMMU_V3_HISILICON_HI161X 0x00000001 /* hi_silicon Hi161x SMMUv3 */ #define ACPI_IORT_SMMU_V3_CAVIUM_CN99XX 0x00000002 /* Cavium CN99xx SMMUv3 */ +#define ACPI_IORT_SMMU_V3_JMND_CORSICA 0x00000003 /*JMND Corsica SMMUv3*/ /* Masks for Flags field above */ #define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1) -- Gitee