// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #include #include #include "arm-smmu-v3.h" #include "../../dma-iommu.h" struct arm_smmu_option_prop { u32 opt; const char *prop; }; static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" }, { ARM_SMMU_OPT_PAGE0_REGS_ONLY, "cavium,cn9900-broken-page1-regspace"}, { 0, NULL}, }; static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = { [EVTQ_MSI_INDEX] = { ARM_SMMU_EVTQ_IRQ_CFG0, ARM_SMMU_EVTQ_IRQ_CFG1, ARM_SMMU_EVTQ_IRQ_CFG2, }, [GERROR_MSI_INDEX] = { ARM_SMMU_GERROR_IRQ_CFG0, ARM_SMMU_GERROR_IRQ_CFG1, ARM_SMMU_GERROR_IRQ_CFG2, }, [PRIQ_MSI_INDEX] = { ARM_SMMU_PRIQ_IRQ_CFG0, ARM_SMMU_PRIQ_IRQ_CFG1, ARM_SMMU_PRIQ_IRQ_CFG2, }, }; static void parse_driver_options(struct arm_smmu_device *smmu) { int i = 0; do { if (of_property_read_bool(smmu->dev->of_node, arm_smmu_options[i].prop)) { smmu->options |= arm_smmu_options[i].opt; dev_notice(smmu->dev, "option %s\n", arm_smmu_options[i].prop); } } while (arm_smmu_options[++i].opt); } static int arm_smmu_device_dt_probe(struct platform_device *pdev, struct arm_smmu_device *smmu, bool *bypass) { struct device *dev = &pdev->dev; u32 cells; *bypass = true; if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells)) dev_err(dev, "missing #iommu-cells property\n"); else if (cells != 1) dev_err(dev, "invalid #iommu-cells value (%d)\n", cells); else *bypass = false; parse_driver_options(smmu); if (of_dma_is_coherent(dev->of_node)) smmu->features |= ARM_SMMU_FEAT_COHERENCY; return 0; } #ifdef CONFIG_ACPI static void acpi_smmu_get_options(u32 model, struct arm_smmu_device *smmu) { switch (model) { case ACPI_IORT_SMMU_V3_CAVIUM_CN99XX: smmu->options |= ARM_SMMU_OPT_PAGE0_REGS_ONLY; break; case ACPI_IORT_SMMU_V3_HISILICON_HI161X: smmu->options |= ARM_SMMU_OPT_SKIP_PREFETCH; break; } dev_notice(smmu->dev, "option mask 0x%x\n", smmu->options); } static int arm_smmu_device_acpi_probe(struct platform_device *pdev, struct arm_smmu_device *smmu, bool *bypass) { struct acpi_iort_smmu_v3 *iort_smmu; struct device *dev = smmu->dev; struct acpi_iort_node *node; node = *(struct acpi_iort_node **)dev_get_platdata(dev); /* Retrieve SMMUv3 specific data */ iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data; acpi_smmu_get_options(iort_smmu->model, smmu); if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE) smmu->features |= ARM_SMMU_FEAT_COHERENCY; *bypass = false; return 0; } #else static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev, struct arm_smmu_device *smmu, bool *bypass) { return -ENODEV; } #endif int arm_smmu_fw_probe(struct platform_device *pdev, struct arm_smmu_device *smmu, bool *bypass) { if (smmu->dev->of_node) return arm_smmu_device_dt_probe(pdev, smmu, bypass); else return arm_smmu_device_acpi_probe(pdev, smmu, bypass); } #ifdef CONFIG_ARM_SMMU_V3_SVA bool __weak arm_smmu_sva_supported(struct arm_smmu_device *smmu) { return false; } #endif #define IIDR_IMPLEMENTER_ARM 0x43b #define IIDR_PRODUCTID_ARM_MMU_600 0x483 #define IIDR_PRODUCTID_ARM_MMU_700 0x487 static void arm_smmu_device_iidr_probe(struct arm_smmu_device *smmu) { u32 reg; unsigned int implementer, productid, variant, revision; reg = readl_relaxed(smmu->base + ARM_SMMU_IIDR); implementer = FIELD_GET(IIDR_IMPLEMENTER, reg); productid = FIELD_GET(IIDR_PRODUCTID, reg); variant = FIELD_GET(IIDR_VARIANT, reg); revision = FIELD_GET(IIDR_REVISION, reg); switch (implementer) { case IIDR_IMPLEMENTER_ARM: switch (productid) { case IIDR_PRODUCTID_ARM_MMU_600: /* Arm erratum 1076982 */ if (variant == 0 && revision <= 2) smmu->features &= ~ARM_SMMU_FEAT_SEV; /* Arm erratum 1209401 */ if (variant < 2) smmu->features &= ~ARM_SMMU_FEAT_NESTING; break; case IIDR_PRODUCTID_ARM_MMU_700: /* Arm erratum 2812531 */ smmu->features &= ~ARM_SMMU_FEAT_BTM; smmu->options |= ARM_SMMU_OPT_CMDQ_FORCE_SYNC; /* Arm errata 2268618, 2812531 */ smmu->features &= ~ARM_SMMU_FEAT_NESTING; break; } break; } } int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) { u32 reg; bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY; u8 split = smmu->strtab_cfg.split; /* IDR0 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0); /* 2-level structures */ if (FIELD_GET(IDR0_ST_LVL, reg) == IDR0_ST_LVL_2LVL) smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB; if (reg & IDR0_CD2L) smmu->features |= ARM_SMMU_FEAT_2_LVL_CDTAB; /* * Translation table endianness. * We currently require the same endianness as the CPU, but this * could be changed later by adding a new IO_PGTABLE_QUIRK. */ switch (FIELD_GET(IDR0_TTENDIAN, reg)) { case IDR0_TTENDIAN_MIXED: smmu->features |= ARM_SMMU_FEAT_TT_LE | ARM_SMMU_FEAT_TT_BE; break; #ifdef __BIG_ENDIAN case IDR0_TTENDIAN_BE: smmu->features |= ARM_SMMU_FEAT_TT_BE; break; #else case IDR0_TTENDIAN_LE: smmu->features |= ARM_SMMU_FEAT_TT_LE; break; #endif default: dev_err(smmu->dev, "unknown/unsupported TT endianness!\n"); return -ENXIO; } /* Boolean feature flags */ if (IS_ENABLED(CONFIG_PCI_PRI) && reg & IDR0_PRI) smmu->features |= ARM_SMMU_FEAT_PRI; if (IS_ENABLED(CONFIG_PCI_ATS) && reg & IDR0_ATS) smmu->features |= ARM_SMMU_FEAT_ATS; if (reg & IDR0_SEV) smmu->features |= ARM_SMMU_FEAT_SEV; if (reg & IDR0_MSI) { smmu->features |= ARM_SMMU_FEAT_MSI; if (coherent) smmu->options |= ARM_SMMU_OPT_MSIPOLL; } if (reg & IDR0_HYP) { smmu->features |= ARM_SMMU_FEAT_HYP; if (cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN)) smmu->features |= ARM_SMMU_FEAT_E2H; } /* * The coherency feature as set by FW is used in preference to the ID * register, but warn on mismatch. */ if (!!(reg & IDR0_COHACC) != coherent) dev_warn(smmu->dev, "IDR0.COHACC overridden by FW configuration (%s)\n", coherent ? "true" : "false"); switch (FIELD_GET(IDR0_STALL_MODEL, reg)) { case IDR0_STALL_MODEL_FORCE: smmu->features |= ARM_SMMU_FEAT_STALL_FORCE; fallthrough; case IDR0_STALL_MODEL_STALL: smmu->features |= ARM_SMMU_FEAT_STALLS; } if (reg & IDR0_S1P) smmu->features |= ARM_SMMU_FEAT_TRANS_S1; if (reg & IDR0_S2P) smmu->features |= ARM_SMMU_FEAT_TRANS_S2; if (!(reg & (IDR0_S1P | IDR0_S2P))) { dev_err(smmu->dev, "no translation support!\n"); return -ENXIO; } /* We only support the AArch64 table format at present */ switch (FIELD_GET(IDR0_TTF, reg)) { case IDR0_TTF_AARCH32_64: smmu->ias = 40; fallthrough; case IDR0_TTF_AARCH64: break; default: dev_err(smmu->dev, "AArch64 table format not supported!\n"); return -ENXIO; } /* ASID/VMID sizes */ smmu->asid_bits = reg & IDR0_ASID16 ? 16 : 8; smmu->vmid_bits = reg & IDR0_VMID16 ? 16 : 8; /* IDR1 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR1); if (reg & (IDR1_TABLES_PRESET | IDR1_QUEUES_PRESET | IDR1_REL)) { dev_err(smmu->dev, "embedded implementation not supported\n"); return -ENXIO; } /* Queue sizes, capped to ensure natural alignment */ smmu->cmdq.q.llq.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT, FIELD_GET(IDR1_CMDQS, reg)); if (smmu->cmdq.q.llq.max_n_shift <= ilog2(CMDQ_BATCH_ENTRIES)) { /* * We don't support splitting up batches, so one batch of * commands plus an extra sync needs to fit inside the command * queue. There's also no way we can handle the weird alignment * restrictions on the base pointer for a unit-length queue. */ dev_err(smmu->dev, "command queue size <= %d entries not supported\n", CMDQ_BATCH_ENTRIES); return -ENXIO; } smmu->evtq.q.llq.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT, FIELD_GET(IDR1_EVTQS, reg)); smmu->priq.q.llq.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT, FIELD_GET(IDR1_PRIQS, reg)); /* SID/SSID sizes */ smmu->ssid_bits = FIELD_GET(IDR1_SSIDSIZE, reg); smmu->sid_bits = FIELD_GET(IDR1_SIDSIZE, reg); smmu->iommu.max_pasids = 1UL << smmu->ssid_bits; if ((split != 6) && (split != 8) && (split != 10)) { dev_err(smmu->dev, "configured split not supported %d\n", split); return -EINVAL; } /* * If the SMMU supports fewer bits than would fill a single L2 stream * table, use a linear table instead. */ if (smmu->sid_bits <= smmu->strtab_cfg.split) smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB; /* IDR3 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3); if (FIELD_GET(IDR3_RIL, reg)) smmu->features |= ARM_SMMU_FEAT_RANGE_INV; /* IDR5 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5); /* Maximum number of outstanding stalls */ smmu->evtq.max_stalls = FIELD_GET(IDR5_STALL_MAX, reg); /* Page sizes */ if (reg & IDR5_GRAN64K) smmu->pgsize_bitmap |= SZ_64K | SZ_512M; if (reg & IDR5_GRAN16K) smmu->pgsize_bitmap |= SZ_16K | SZ_32M; if (reg & IDR5_GRAN4K) smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G; /* Input address size */ if (FIELD_GET(IDR5_VAX, reg) == IDR5_VAX_52_BIT) smmu->features |= ARM_SMMU_FEAT_VAX; /* Output address size */ switch (FIELD_GET(IDR5_OAS, reg)) { case IDR5_OAS_32_BIT: smmu->oas = 32; break; case IDR5_OAS_36_BIT: smmu->oas = 36; break; case IDR5_OAS_40_BIT: smmu->oas = 40; break; case IDR5_OAS_42_BIT: smmu->oas = 42; break; case IDR5_OAS_44_BIT: smmu->oas = 44; break; case IDR5_OAS_52_BIT: smmu->oas = 52; smmu->pgsize_bitmap |= 1ULL << 42; /* 4TB */ break; default: dev_info(smmu->dev, "unknown output address size. Truncating to 48-bit\n"); fallthrough; case IDR5_OAS_48_BIT: smmu->oas = 48; } /* Set the DMA mask for our table walker */ if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas))) dev_warn(smmu->dev, "failed to set DMA mask for table walker\n"); smmu->ias = max(smmu->ias, smmu->oas); if ((smmu->features & ARM_SMMU_FEAT_TRANS_S1) && (smmu->features & ARM_SMMU_FEAT_TRANS_S2)) smmu->features |= ARM_SMMU_FEAT_NESTING; arm_smmu_device_iidr_probe(smmu); if (arm_smmu_sva_supported(smmu)) smmu->features |= ARM_SMMU_FEAT_SVA; dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n", smmu->ias, smmu->oas, smmu->features); return 0; } int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val, unsigned int reg_off, unsigned int ack_off) { u32 reg; writel_relaxed(val, smmu->base + reg_off); return readl_relaxed_poll_timeout(smmu->base + ack_off, reg, reg == val, 1, ARM_SMMU_POLL_TIMEOUT_US); } /* GBPA is "special" */ int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr) { int ret; u32 reg, __iomem *gbpa = smmu->base + ARM_SMMU_GBPA; ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE), 1, ARM_SMMU_POLL_TIMEOUT_US); if (ret) return ret; reg &= ~clr; reg |= set; writel_relaxed(reg | GBPA_UPDATE, gbpa); ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE), 1, ARM_SMMU_POLL_TIMEOUT_US); if (ret) dev_err(smmu->dev, "GBPA not responding to update\n"); return ret; } int arm_smmu_device_disable(struct arm_smmu_device *smmu) { int ret; ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_CR0, ARM_SMMU_CR0ACK); if (ret) dev_err(smmu->dev, "failed to clear cr0\n"); return ret; } bool arm_smmu_capable(struct device *dev, enum iommu_cap cap) { struct arm_smmu_master *master = dev_iommu_priv_get(dev); switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: /* Assume that a coherent TCU implies coherent TBUs */ return master->smmu->features & ARM_SMMU_FEAT_COHERENCY; case IOMMU_CAP_NOEXEC: case IOMMU_CAP_DEFERRED_FLUSH: return true; default: return false; } } struct iommu_group *arm_smmu_device_group(struct device *dev) { struct iommu_group *group; /* * We don't support devices sharing stream IDs other than PCI RID * aliases, since the necessary ID-to-device lookup becomes rather * impractical given a potential sparse 32-bit stream ID space. */ if (dev_is_pci(dev)) group = pci_device_group(dev); else group = generic_device_group(dev); return group; } int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) { return iommu_fwspec_add_ids(dev, args->args, 1); } void arm_smmu_get_resv_regions(struct device *dev, struct list_head *head) { struct iommu_resv_region *region; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, prot, IOMMU_RESV_SW_MSI, GFP_KERNEL); if (!region) return; list_add_tail(®ion->list, head); iommu_dma_get_resv_regions(dev, head); } int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, struct arm_smmu_queue *q, void __iomem *page, unsigned long prod_off, unsigned long cons_off, size_t dwords, const char *name) { size_t qsz; do { qsz = ((1 << q->llq.max_n_shift) * dwords) << 3; q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL); if (q->base || qsz < PAGE_SIZE) break; q->llq.max_n_shift--; } while (1); if (!q->base) { dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes) for %s\n", qsz, name); return -ENOMEM; } if (!WARN_ON(q->base_dma & (qsz - 1))) { dev_info(smmu->dev, "allocated %u entries for %s\n", 1 << q->llq.max_n_shift, name); } q->prod_reg = page + prod_off; q->cons_reg = page + cons_off; q->ent_dwords = dwords; q->q_base = Q_BASE_RWA; q->q_base |= q->base_dma & Q_BASE_ADDR_MASK; q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->llq.max_n_shift); q->llq.prod = q->llq.cons = 0; return 0; } /* Stream table initialization functions */ void arm_smmu_write_strtab_l1_desc(__le64 *dst, struct arm_smmu_strtab_l1_desc *desc) { u64 val = 0; val |= FIELD_PREP(STRTAB_L1_DESC_SPAN, desc->span); val |= desc->l2ptr_dma & STRTAB_L1_DESC_L2PTR_MASK; /* See comment in arm_smmu_write_ctx_desc() */ WRITE_ONCE(*dst, cpu_to_le64(val)); } static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu) { unsigned int i; struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; void *strtab = smmu->strtab_cfg.strtab; cfg->l1_desc = devm_kcalloc(smmu->dev, cfg->num_l1_ents, sizeof(*cfg->l1_desc), GFP_KERNEL); if (!cfg->l1_desc) return -ENOMEM; for (i = 0; i < cfg->num_l1_ents; ++i) { arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]); strtab += STRTAB_L1_DESC_DWORDS << 3; } return 0; } static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu) { void *strtab; u64 reg; u32 size, l1size; struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; /* Calculate the L1 size, capped to the SIDSIZE. */ size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3); size = min(size, smmu->sid_bits - smmu->strtab_cfg.split); cfg->num_l1_ents = 1 << size; size += smmu->strtab_cfg.split; if (size < smmu->sid_bits) dev_warn(smmu->dev, "2-level strtab only covers %u/%u bits of SID\n", size, smmu->sid_bits); l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3); strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma, GFP_KERNEL); if (!strtab) { dev_err(smmu->dev, "failed to allocate l1 stream table (%u bytes)\n", l1size); return -ENOMEM; } cfg->strtab = strtab; /* Configure strtab_base_cfg for 2 levels */ reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_2LVL); reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, size); reg |= FIELD_PREP(STRTAB_BASE_CFG_SPLIT, smmu->strtab_cfg.split); cfg->strtab_base_cfg = reg; return arm_smmu_init_l1_strtab(smmu); } static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu) { void *strtab; u64 reg; u32 size; struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3); strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma, GFP_KERNEL); if (!strtab) { dev_err(smmu->dev, "failed to allocate linear stream table (%u bytes)\n", size); return -ENOMEM; } cfg->strtab = strtab; cfg->num_l1_ents = 1 << smmu->sid_bits; /* Configure strtab_base_cfg for a linear table covering all SIDs */ reg = FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_LINEAR); reg |= FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits); cfg->strtab_base_cfg = reg; return 0; } int arm_smmu_init_strtab(struct arm_smmu_device *smmu) { u64 reg; int ret; if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) ret = arm_smmu_init_strtab_2lvl(smmu); else ret = arm_smmu_init_strtab_linear(smmu); if (ret) return ret; /* Set the strtab base address */ reg = smmu->strtab_cfg.strtab_dma & STRTAB_BASE_ADDR_MASK; reg |= STRTAB_BASE_RA; smmu->strtab_cfg.strtab_base = reg; ida_init(&smmu->vmid_map); return 0; } static void arm_smmu_free_msis(void *data) { struct device *dev = data; platform_msi_domain_free_irqs(dev); } static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) { phys_addr_t doorbell; struct device *dev = msi_desc_to_dev(desc); struct arm_smmu_device *smmu = dev_get_drvdata(dev); phys_addr_t *cfg = arm_smmu_msi_cfg[desc->msi_index]; doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo; doorbell &= MSI_CFG0_ADDR_MASK; writeq_relaxed(doorbell, smmu->base + cfg[0]); writel_relaxed(msg->data, smmu->base + cfg[1]); writel_relaxed(ARM_SMMU_MEMATTR_DEVICE_nGnRE, smmu->base + cfg[2]); } static void arm_smmu_setup_msis(struct arm_smmu_device *smmu) { int ret, nvec = ARM_SMMU_MAX_MSIS; struct device *dev = smmu->dev; /* Clear the MSI address regs */ writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0); writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0); if (smmu->features & ARM_SMMU_FEAT_PRI) writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0); else nvec--; if (!(smmu->features & ARM_SMMU_FEAT_MSI)) return; if (!dev->msi.domain) { dev_info(smmu->dev, "msi_domain absent - falling back to wired irqs\n"); return; } /* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */ ret = platform_msi_domain_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg); if (ret) { dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n"); return; } smmu->evtq.q.irq = msi_get_virq(dev, EVTQ_MSI_INDEX); smmu->gerr_irq = msi_get_virq(dev, GERROR_MSI_INDEX); smmu->priq.q.irq = msi_get_virq(dev, PRIQ_MSI_INDEX); /* Add callback to free MSIs on teardown */ devm_add_action(dev, arm_smmu_free_msis, dev); } void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu, irqreturn_t evtqirq(int irq, void *dev), irqreturn_t gerrorirq(int irq, void *dev), irqreturn_t priirq(int irq, void *dev)) { int irq, ret; arm_smmu_setup_msis(smmu); /* Request interrupt lines */ irq = smmu->evtq.q.irq; if (irq) { ret = devm_request_threaded_irq(smmu->dev, irq, NULL, evtqirq, IRQF_ONESHOT, "arm-smmu-v3-evtq", smmu); if (ret < 0) dev_warn(smmu->dev, "failed to enable evtq irq\n"); } else { dev_warn(smmu->dev, "no evtq irq - events will not be reported!\n"); } irq = smmu->gerr_irq; if (irq) { ret = devm_request_irq(smmu->dev, irq, gerrorirq, 0, "arm-smmu-v3-gerror", smmu); if (ret < 0) dev_warn(smmu->dev, "failed to enable gerror irq\n"); } else { dev_warn(smmu->dev, "no gerr irq - errors will not be reported!\n"); } if (smmu->features & ARM_SMMU_FEAT_PRI) { irq = smmu->priq.q.irq; if (irq) { ret = devm_request_threaded_irq(smmu->dev, irq, NULL, priirq, IRQF_ONESHOT, "arm-smmu-v3-priq", smmu); if (ret < 0) dev_warn(smmu->dev, "failed to enable priq irq\n"); } else { dev_warn(smmu->dev, "no priq irq - PRI will be broken\n"); } } } void arm_smmu_probe_irq(struct platform_device *pdev, struct arm_smmu_device *smmu) { int irq; irq = platform_get_irq_byname_optional(pdev, "combined"); if (irq > 0) smmu->combined_irq = irq; else { irq = platform_get_irq_byname_optional(pdev, "eventq"); if (irq > 0) smmu->evtq.q.irq = irq; irq = platform_get_irq_byname_optional(pdev, "priq"); if (irq > 0) smmu->priq.q.irq = irq; irq = platform_get_irq_byname_optional(pdev, "gerror"); if (irq > 0) smmu->gerr_irq = irq; } } int arm_smmu_register_iommu(struct arm_smmu_device *smmu, struct iommu_ops *ops, phys_addr_t ioaddr) { int ret; struct device *dev = smmu->dev; ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL, "smmu3.%pa", &ioaddr); if (ret) return ret; ret = iommu_device_register(&smmu->iommu, ops, dev); if (ret) { dev_err(dev, "Failed to register iommu\n"); iommu_device_sysfs_remove(&smmu->iommu); return ret; } return 0; } void arm_smmu_unregister_iommu(struct arm_smmu_device *smmu) { iommu_device_unregister(&smmu->iommu); iommu_device_sysfs_remove(&smmu->iommu); }