150528752SMarc Zyngier // SPDX-License-Identifier: GPL-2.0 250528752SMarc Zyngier /* 350528752SMarc Zyngier * Copyright (C) 2018 ARM Limited, All Rights Reserved. 450528752SMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com> 550528752SMarc Zyngier */ 650528752SMarc Zyngier 750528752SMarc Zyngier #define pr_fmt(fmt) "GICv3: " fmt 850528752SMarc Zyngier 950528752SMarc Zyngier #include <linux/dma-iommu.h> 1050528752SMarc Zyngier #include <linux/irq.h> 1150528752SMarc Zyngier #include <linux/irqdomain.h> 1250528752SMarc Zyngier #include <linux/kernel.h> 1350528752SMarc Zyngier #include <linux/msi.h> 1450528752SMarc Zyngier #include <linux/of_address.h> 1538985351SMarc Zyngier #include <linux/of_pci.h> 1650528752SMarc Zyngier #include <linux/slab.h> 1750528752SMarc Zyngier #include <linux/spinlock.h> 1850528752SMarc Zyngier 1950528752SMarc Zyngier #include <linux/irqchip/arm-gic-v3.h> 2050528752SMarc Zyngier 2150528752SMarc Zyngier struct mbi_range { 2250528752SMarc Zyngier u32 spi_start; 2350528752SMarc Zyngier u32 nr_spis; 2450528752SMarc Zyngier unsigned long *bm; 2550528752SMarc Zyngier }; 2650528752SMarc Zyngier 27c530bb8aSYang Yingliang static DEFINE_MUTEX(mbi_lock); 2850528752SMarc Zyngier static phys_addr_t mbi_phys_base; 2950528752SMarc Zyngier static struct mbi_range *mbi_ranges; 3050528752SMarc Zyngier static unsigned int mbi_range_nr; 3150528752SMarc Zyngier 3250528752SMarc Zyngier static struct irq_chip mbi_irq_chip = { 3350528752SMarc Zyngier .name = "MBI", 3450528752SMarc Zyngier .irq_mask = irq_chip_mask_parent, 3550528752SMarc Zyngier .irq_unmask = irq_chip_unmask_parent, 3650528752SMarc Zyngier .irq_eoi = irq_chip_eoi_parent, 3750528752SMarc Zyngier .irq_set_type = irq_chip_set_type_parent, 3850528752SMarc Zyngier .irq_set_affinity = irq_chip_set_affinity_parent, 3950528752SMarc Zyngier }; 4050528752SMarc Zyngier 4150528752SMarc Zyngier static int mbi_irq_gic_domain_alloc(struct irq_domain *domain, 4250528752SMarc Zyngier unsigned int virq, 4350528752SMarc Zyngier irq_hw_number_t hwirq) 4450528752SMarc Zyngier { 4550528752SMarc Zyngier struct irq_fwspec fwspec; 4650528752SMarc Zyngier struct irq_data *d; 4750528752SMarc Zyngier int err; 4850528752SMarc Zyngier 4950528752SMarc Zyngier /* 5050528752SMarc Zyngier * Using ACPI? There is no MBI support in the spec, you 5150528752SMarc Zyngier * shouldn't even be here. 5250528752SMarc Zyngier */ 5350528752SMarc Zyngier if (!is_of_node(domain->parent->fwnode)) 5450528752SMarc Zyngier return -EINVAL; 5550528752SMarc Zyngier 5650528752SMarc Zyngier /* 5750528752SMarc Zyngier * Let's default to edge. This is consistent with traditional 5850528752SMarc Zyngier * MSIs, and systems requiring level signaling will just 5950528752SMarc Zyngier * enforce the trigger on their own. 6050528752SMarc Zyngier */ 6150528752SMarc Zyngier fwspec.fwnode = domain->parent->fwnode; 6250528752SMarc Zyngier fwspec.param_count = 3; 6350528752SMarc Zyngier fwspec.param[0] = 0; 6450528752SMarc Zyngier fwspec.param[1] = hwirq - 32; 6550528752SMarc Zyngier fwspec.param[2] = IRQ_TYPE_EDGE_RISING; 6650528752SMarc Zyngier 6750528752SMarc Zyngier err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); 6850528752SMarc Zyngier if (err) 6950528752SMarc Zyngier return err; 7050528752SMarc Zyngier 7150528752SMarc Zyngier d = irq_domain_get_irq_data(domain->parent, virq); 7250528752SMarc Zyngier return d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); 7350528752SMarc Zyngier } 7450528752SMarc Zyngier 7550528752SMarc Zyngier static void mbi_free_msi(struct mbi_range *mbi, unsigned int hwirq, 7650528752SMarc Zyngier int nr_irqs) 7750528752SMarc Zyngier { 7850528752SMarc Zyngier mutex_lock(&mbi_lock); 7950528752SMarc Zyngier bitmap_release_region(mbi->bm, hwirq - mbi->spi_start, 8050528752SMarc Zyngier get_count_order(nr_irqs)); 8150528752SMarc Zyngier mutex_unlock(&mbi_lock); 8250528752SMarc Zyngier } 8350528752SMarc Zyngier 8450528752SMarc Zyngier static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 8550528752SMarc Zyngier unsigned int nr_irqs, void *args) 8650528752SMarc Zyngier { 87*73103975SJulien Grall msi_alloc_info_t *info = args; 8850528752SMarc Zyngier struct mbi_range *mbi = NULL; 8950528752SMarc Zyngier int hwirq, offset, i, err = 0; 9050528752SMarc Zyngier 9150528752SMarc Zyngier mutex_lock(&mbi_lock); 9250528752SMarc Zyngier for (i = 0; i < mbi_range_nr; i++) { 9350528752SMarc Zyngier offset = bitmap_find_free_region(mbi_ranges[i].bm, 9450528752SMarc Zyngier mbi_ranges[i].nr_spis, 9550528752SMarc Zyngier get_count_order(nr_irqs)); 9650528752SMarc Zyngier if (offset >= 0) { 9750528752SMarc Zyngier mbi = &mbi_ranges[i]; 9850528752SMarc Zyngier break; 9950528752SMarc Zyngier } 10050528752SMarc Zyngier } 10150528752SMarc Zyngier mutex_unlock(&mbi_lock); 10250528752SMarc Zyngier 10350528752SMarc Zyngier if (!mbi) 10450528752SMarc Zyngier return -ENOSPC; 10550528752SMarc Zyngier 10650528752SMarc Zyngier hwirq = mbi->spi_start + offset; 10750528752SMarc Zyngier 108*73103975SJulien Grall err = iommu_dma_prepare_msi(info->desc, 109*73103975SJulien Grall mbi_phys_base + GICD_SETSPI_NSR); 110*73103975SJulien Grall if (err) 111*73103975SJulien Grall return err; 112*73103975SJulien Grall 11350528752SMarc Zyngier for (i = 0; i < nr_irqs; i++) { 11450528752SMarc Zyngier err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i); 11550528752SMarc Zyngier if (err) 11650528752SMarc Zyngier goto fail; 11750528752SMarc Zyngier 11850528752SMarc Zyngier irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, 11950528752SMarc Zyngier &mbi_irq_chip, mbi); 12050528752SMarc Zyngier } 12150528752SMarc Zyngier 12250528752SMarc Zyngier return 0; 12350528752SMarc Zyngier 12450528752SMarc Zyngier fail: 12550528752SMarc Zyngier irq_domain_free_irqs_parent(domain, virq, nr_irqs); 12650528752SMarc Zyngier mbi_free_msi(mbi, hwirq, nr_irqs); 12750528752SMarc Zyngier return err; 12850528752SMarc Zyngier } 12950528752SMarc Zyngier 13050528752SMarc Zyngier static void mbi_irq_domain_free(struct irq_domain *domain, 13150528752SMarc Zyngier unsigned int virq, unsigned int nr_irqs) 13250528752SMarc Zyngier { 13350528752SMarc Zyngier struct irq_data *d = irq_domain_get_irq_data(domain, virq); 13450528752SMarc Zyngier struct mbi_range *mbi = irq_data_get_irq_chip_data(d); 13550528752SMarc Zyngier 13650528752SMarc Zyngier mbi_free_msi(mbi, d->hwirq, nr_irqs); 13750528752SMarc Zyngier irq_domain_free_irqs_parent(domain, virq, nr_irqs); 13850528752SMarc Zyngier } 13950528752SMarc Zyngier 14050528752SMarc Zyngier static const struct irq_domain_ops mbi_domain_ops = { 14150528752SMarc Zyngier .alloc = mbi_irq_domain_alloc, 14250528752SMarc Zyngier .free = mbi_irq_domain_free, 14350528752SMarc Zyngier }; 14450528752SMarc Zyngier 14550528752SMarc Zyngier static void mbi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 14650528752SMarc Zyngier { 14750528752SMarc Zyngier msg[0].address_hi = upper_32_bits(mbi_phys_base + GICD_SETSPI_NSR); 14850528752SMarc Zyngier msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR); 14950528752SMarc Zyngier msg[0].data = data->parent_data->hwirq; 15050528752SMarc Zyngier 151*73103975SJulien Grall iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg); 15250528752SMarc Zyngier } 15350528752SMarc Zyngier 15438985351SMarc Zyngier #ifdef CONFIG_PCI_MSI 15538985351SMarc Zyngier /* PCI-specific irqchip */ 15638985351SMarc Zyngier static void mbi_mask_msi_irq(struct irq_data *d) 15738985351SMarc Zyngier { 15838985351SMarc Zyngier pci_msi_mask_irq(d); 15938985351SMarc Zyngier irq_chip_mask_parent(d); 16038985351SMarc Zyngier } 16138985351SMarc Zyngier 16238985351SMarc Zyngier static void mbi_unmask_msi_irq(struct irq_data *d) 16338985351SMarc Zyngier { 16438985351SMarc Zyngier pci_msi_unmask_irq(d); 16538985351SMarc Zyngier irq_chip_unmask_parent(d); 16638985351SMarc Zyngier } 16738985351SMarc Zyngier 16838985351SMarc Zyngier static struct irq_chip mbi_msi_irq_chip = { 16938985351SMarc Zyngier .name = "MSI", 17038985351SMarc Zyngier .irq_mask = mbi_mask_msi_irq, 17138985351SMarc Zyngier .irq_unmask = mbi_unmask_msi_irq, 17238985351SMarc Zyngier .irq_eoi = irq_chip_eoi_parent, 17338985351SMarc Zyngier .irq_compose_msi_msg = mbi_compose_msi_msg, 17438985351SMarc Zyngier .irq_write_msi_msg = pci_msi_domain_write_msg, 17538985351SMarc Zyngier }; 17638985351SMarc Zyngier 17738985351SMarc Zyngier static struct msi_domain_info mbi_msi_domain_info = { 17838985351SMarc Zyngier .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 17938985351SMarc Zyngier MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI), 18038985351SMarc Zyngier .chip = &mbi_msi_irq_chip, 18138985351SMarc Zyngier }; 18238985351SMarc Zyngier 18338985351SMarc Zyngier static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, 18438985351SMarc Zyngier struct irq_domain **pci_domain) 18538985351SMarc Zyngier { 18638985351SMarc Zyngier *pci_domain = pci_msi_create_irq_domain(nexus_domain->parent->fwnode, 18738985351SMarc Zyngier &mbi_msi_domain_info, 18838985351SMarc Zyngier nexus_domain); 18938985351SMarc Zyngier if (!*pci_domain) 19038985351SMarc Zyngier return -ENOMEM; 19138985351SMarc Zyngier 19238985351SMarc Zyngier return 0; 19338985351SMarc Zyngier } 19438985351SMarc Zyngier #else 19538985351SMarc Zyngier static int mbi_allocate_pci_domain(struct irq_domain *nexus_domain, 19638985351SMarc Zyngier struct irq_domain **pci_domain) 19738985351SMarc Zyngier { 19838985351SMarc Zyngier *pci_domain = NULL; 19938985351SMarc Zyngier return 0; 20038985351SMarc Zyngier } 20138985351SMarc Zyngier #endif 20238985351SMarc Zyngier 20350528752SMarc Zyngier static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg) 20450528752SMarc Zyngier { 20550528752SMarc Zyngier mbi_compose_msi_msg(data, msg); 20650528752SMarc Zyngier 20750528752SMarc Zyngier msg[1].address_hi = upper_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); 20850528752SMarc Zyngier msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); 20950528752SMarc Zyngier msg[1].data = data->parent_data->hwirq; 21050528752SMarc Zyngier 211*73103975SJulien Grall iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), &msg[1]); 21250528752SMarc Zyngier } 21350528752SMarc Zyngier 21450528752SMarc Zyngier /* Platform-MSI specific irqchip */ 21550528752SMarc Zyngier static struct irq_chip mbi_pmsi_irq_chip = { 21650528752SMarc Zyngier .name = "pMSI", 21750528752SMarc Zyngier .irq_set_type = irq_chip_set_type_parent, 21850528752SMarc Zyngier .irq_compose_msi_msg = mbi_compose_mbi_msg, 21950528752SMarc Zyngier .flags = IRQCHIP_SUPPORTS_LEVEL_MSI, 22050528752SMarc Zyngier }; 22150528752SMarc Zyngier 22250528752SMarc Zyngier static struct msi_domain_ops mbi_pmsi_ops = { 22350528752SMarc Zyngier }; 22450528752SMarc Zyngier 22550528752SMarc Zyngier static struct msi_domain_info mbi_pmsi_domain_info = { 22650528752SMarc Zyngier .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 22750528752SMarc Zyngier MSI_FLAG_LEVEL_CAPABLE), 22850528752SMarc Zyngier .ops = &mbi_pmsi_ops, 22950528752SMarc Zyngier .chip = &mbi_pmsi_irq_chip, 23050528752SMarc Zyngier }; 23150528752SMarc Zyngier 23250528752SMarc Zyngier static int mbi_allocate_domains(struct irq_domain *parent) 23350528752SMarc Zyngier { 23438985351SMarc Zyngier struct irq_domain *nexus_domain, *pci_domain, *plat_domain; 23538985351SMarc Zyngier int err; 23650528752SMarc Zyngier 23750528752SMarc Zyngier nexus_domain = irq_domain_create_tree(parent->fwnode, 23850528752SMarc Zyngier &mbi_domain_ops, NULL); 23950528752SMarc Zyngier if (!nexus_domain) 24050528752SMarc Zyngier return -ENOMEM; 24150528752SMarc Zyngier 24250528752SMarc Zyngier irq_domain_update_bus_token(nexus_domain, DOMAIN_BUS_NEXUS); 24350528752SMarc Zyngier nexus_domain->parent = parent; 24450528752SMarc Zyngier 24538985351SMarc Zyngier err = mbi_allocate_pci_domain(nexus_domain, &pci_domain); 24638985351SMarc Zyngier 24750528752SMarc Zyngier plat_domain = platform_msi_create_irq_domain(parent->fwnode, 24850528752SMarc Zyngier &mbi_pmsi_domain_info, 24950528752SMarc Zyngier nexus_domain); 25050528752SMarc Zyngier 25138985351SMarc Zyngier if (err || !plat_domain) { 25238985351SMarc Zyngier if (plat_domain) 25350528752SMarc Zyngier irq_domain_remove(plat_domain); 25438985351SMarc Zyngier if (pci_domain) 25538985351SMarc Zyngier irq_domain_remove(pci_domain); 25650528752SMarc Zyngier irq_domain_remove(nexus_domain); 25750528752SMarc Zyngier return -ENOMEM; 25850528752SMarc Zyngier } 25950528752SMarc Zyngier 26050528752SMarc Zyngier return 0; 26150528752SMarc Zyngier } 26250528752SMarc Zyngier 26350528752SMarc Zyngier int __init mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent) 26450528752SMarc Zyngier { 26550528752SMarc Zyngier struct device_node *np; 26650528752SMarc Zyngier const __be32 *reg; 26750528752SMarc Zyngier int ret, n; 26850528752SMarc Zyngier 26950528752SMarc Zyngier np = to_of_node(fwnode); 27050528752SMarc Zyngier 27150528752SMarc Zyngier if (!of_property_read_bool(np, "msi-controller")) 27250528752SMarc Zyngier return 0; 27350528752SMarc Zyngier 27450528752SMarc Zyngier n = of_property_count_elems_of_size(np, "mbi-ranges", sizeof(u32)); 27550528752SMarc Zyngier if (n <= 0 || n % 2) 27650528752SMarc Zyngier return -EINVAL; 27750528752SMarc Zyngier 27850528752SMarc Zyngier mbi_range_nr = n / 2; 27950528752SMarc Zyngier mbi_ranges = kcalloc(mbi_range_nr, sizeof(*mbi_ranges), GFP_KERNEL); 28050528752SMarc Zyngier if (!mbi_ranges) 28150528752SMarc Zyngier return -ENOMEM; 28250528752SMarc Zyngier 28350528752SMarc Zyngier for (n = 0; n < mbi_range_nr; n++) { 28450528752SMarc Zyngier ret = of_property_read_u32_index(np, "mbi-ranges", n * 2, 28550528752SMarc Zyngier &mbi_ranges[n].spi_start); 28650528752SMarc Zyngier if (ret) 28750528752SMarc Zyngier goto err_free_mbi; 28850528752SMarc Zyngier ret = of_property_read_u32_index(np, "mbi-ranges", n * 2 + 1, 28950528752SMarc Zyngier &mbi_ranges[n].nr_spis); 29050528752SMarc Zyngier if (ret) 29150528752SMarc Zyngier goto err_free_mbi; 29250528752SMarc Zyngier 29350528752SMarc Zyngier mbi_ranges[n].bm = kcalloc(BITS_TO_LONGS(mbi_ranges[n].nr_spis), 29450528752SMarc Zyngier sizeof(long), GFP_KERNEL); 29550528752SMarc Zyngier if (!mbi_ranges[n].bm) { 29650528752SMarc Zyngier ret = -ENOMEM; 29750528752SMarc Zyngier goto err_free_mbi; 29850528752SMarc Zyngier } 29950528752SMarc Zyngier pr_info("MBI range [%d:%d]\n", mbi_ranges[n].spi_start, 30050528752SMarc Zyngier mbi_ranges[n].spi_start + mbi_ranges[n].nr_spis - 1); 30150528752SMarc Zyngier } 30250528752SMarc Zyngier 30350528752SMarc Zyngier reg = of_get_property(np, "mbi-alias", NULL); 30450528752SMarc Zyngier if (reg) { 30550528752SMarc Zyngier mbi_phys_base = of_translate_address(np, reg); 30650528752SMarc Zyngier if (mbi_phys_base == OF_BAD_ADDR) { 30750528752SMarc Zyngier ret = -ENXIO; 30850528752SMarc Zyngier goto err_free_mbi; 30950528752SMarc Zyngier } 31050528752SMarc Zyngier } else { 31150528752SMarc Zyngier struct resource res; 31250528752SMarc Zyngier 31350528752SMarc Zyngier if (of_address_to_resource(np, 0, &res)) { 31450528752SMarc Zyngier ret = -ENXIO; 31550528752SMarc Zyngier goto err_free_mbi; 31650528752SMarc Zyngier } 31750528752SMarc Zyngier 31850528752SMarc Zyngier mbi_phys_base = res.start; 31950528752SMarc Zyngier } 32050528752SMarc Zyngier 32150528752SMarc Zyngier pr_info("Using MBI frame %pa\n", &mbi_phys_base); 32250528752SMarc Zyngier 32350528752SMarc Zyngier ret = mbi_allocate_domains(parent); 32450528752SMarc Zyngier if (ret) 32550528752SMarc Zyngier goto err_free_mbi; 32650528752SMarc Zyngier 32750528752SMarc Zyngier return 0; 32850528752SMarc Zyngier 32950528752SMarc Zyngier err_free_mbi: 33050528752SMarc Zyngier if (mbi_ranges) { 33150528752SMarc Zyngier for (n = 0; n < mbi_range_nr; n++) 33250528752SMarc Zyngier kfree(mbi_ranges[n].bm); 33350528752SMarc Zyngier kfree(mbi_ranges); 33450528752SMarc Zyngier } 33550528752SMarc Zyngier 33650528752SMarc Zyngier return ret; 33750528752SMarc Zyngier } 338