summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-19 13:58:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-19 13:58:45 -0400
commitd9351ea14ddca708d3cb384f828af4bf82fcc772 (patch)
tree90c5fe9067f1005ce512c63b2e664a670af72b4f /drivers/irqchip
parent39feaa3ff4453594297574e116a55bd6d5371f37 (diff)
parentfb4e0592654adb31bc6f3a738d6499b816a655d6 (diff)
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull IRQ chip updates from Ingo Molnar: "A late irqchips update: - New TI INTR/INTA set of drivers - Rewrite of the stm32mp1-exti driver as a platform driver - Update the IOMMU MSI mapping API to be RT friendly - A number of cleanups and other low impact fixes" * 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits) iommu/dma-iommu: Remove iommu_dma_map_msi_msg() irqchip/gic-v3-mbi: Don't map the MSI page in mbi_compose_m{b, s}i_msg() irqchip/ls-scfg-msi: Don't map the MSI page in ls_scfg_msi_compose_msg() irqchip/gic-v3-its: Don't map the MSI page in its_irq_compose_msi_msg() irqchip/gicv2m: Don't map the MSI page in gicv2m_compose_msi_msg() iommu/dma-iommu: Split iommu_dma_map_msi_msg() in two parts genirq/msi: Add a new field in msi_desc to store an IOMMU cookie arm64: arch_k3: Enable interrupt controller drivers irqchip/ti-sci-inta: Add msi domain support soc: ti: Add MSI domain bus support for Interrupt Aggregator irqchip/ti-sci-inta: Add support for Interrupt Aggregator driver dt-bindings: irqchip: Introduce TISCI Interrupt Aggregator bindings irqchip/ti-sci-intr: Add support for Interrupt Router driver dt-bindings: irqchip: Introduce TISCI Interrupt router bindings gpio: thunderx: Use the default parent apis for {request,release}_resources genirq: Introduce irq_chip_{request,release}_resource_parent() apis firmware: ti_sci: Add helper apis to manage resources firmware: ti_sci: Add RM mapping table for am654 firmware: ti_sci: Add support for IRQ management firmware: ti_sci: Add support for RM core ops ...
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/Kconfig27
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-bcm7038-l1.c3
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c3
-rw-r--r--drivers/irqchip/irq-brcmstb-l2.c2
-rw-r--r--drivers/irqchip/irq-gic-pm.c76
-rw-r--r--drivers/irqchip/irq-gic-v2m.c8
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c84
-rw-r--r--drivers/irqchip/irq-gic-v3-mbi.c10
-rw-r--r--drivers/irqchip/irq-imx-irqsteer.c4
-rw-r--r--drivers/irqchip/irq-ls-scfg-msi.c7
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c4
-rw-r--r--drivers/irqchip/irq-stm32-exti.c233
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c615
-rw-r--r--drivers/irqchip/irq-ti-sci-intr.c275
15 files changed, 1166 insertions, 187 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index cf7984991062..1c1f3f66dfd3 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -6,7 +6,6 @@ config IRQCHIP
6 6
7config ARM_GIC 7config ARM_GIC
8 bool 8 bool
9 select IRQ_DOMAIN
10 select IRQ_DOMAIN_HIERARCHY 9 select IRQ_DOMAIN_HIERARCHY
11 select GENERIC_IRQ_MULTI_HANDLER 10 select GENERIC_IRQ_MULTI_HANDLER
12 select GENERIC_IRQ_EFFECTIVE_AFF_MASK 11 select GENERIC_IRQ_EFFECTIVE_AFF_MASK
@@ -33,7 +32,6 @@ config GIC_NON_BANKED
33 32
34config ARM_GIC_V3 33config ARM_GIC_V3
35 bool 34 bool
36 select IRQ_DOMAIN
37 select GENERIC_IRQ_MULTI_HANDLER 35 select GENERIC_IRQ_MULTI_HANDLER
38 select IRQ_DOMAIN_HIERARCHY 36 select IRQ_DOMAIN_HIERARCHY
39 select PARTITION_PERCPU 37 select PARTITION_PERCPU
@@ -59,7 +57,6 @@ config ARM_GIC_V3_ITS_FSL_MC
59 57
60config ARM_NVIC 58config ARM_NVIC
61 bool 59 bool
62 select IRQ_DOMAIN
63 select IRQ_DOMAIN_HIERARCHY 60 select IRQ_DOMAIN_HIERARCHY
64 select GENERIC_IRQ_CHIP 61 select GENERIC_IRQ_CHIP
65 62
@@ -358,7 +355,6 @@ config STM32_EXTI
358config QCOM_IRQ_COMBINER 355config QCOM_IRQ_COMBINER
359 bool "QCOM IRQ combiner support" 356 bool "QCOM IRQ combiner support"
360 depends on ARCH_QCOM && ACPI 357 depends on ARCH_QCOM && ACPI
361 select IRQ_DOMAIN
362 select IRQ_DOMAIN_HIERARCHY 358 select IRQ_DOMAIN_HIERARCHY
363 help 359 help
364 Say yes here to add support for the IRQ combiner devices embedded 360 Say yes here to add support for the IRQ combiner devices embedded
@@ -375,7 +371,6 @@ config IRQ_UNIPHIER_AIDET
375config MESON_IRQ_GPIO 371config MESON_IRQ_GPIO
376 bool "Meson GPIO Interrupt Multiplexer" 372 bool "Meson GPIO Interrupt Multiplexer"
377 depends on ARCH_MESON 373 depends on ARCH_MESON
378 select IRQ_DOMAIN
379 select IRQ_DOMAIN_HIERARCHY 374 select IRQ_DOMAIN_HIERARCHY
380 help 375 help
381 Support Meson SoC Family GPIO Interrupt Multiplexer 376 Support Meson SoC Family GPIO Interrupt Multiplexer
@@ -391,7 +386,6 @@ config GOLDFISH_PIC
391config QCOM_PDC 386config QCOM_PDC
392 bool "QCOM PDC" 387 bool "QCOM PDC"
393 depends on ARCH_QCOM 388 depends on ARCH_QCOM
394 select IRQ_DOMAIN
395 select IRQ_DOMAIN_HIERARCHY 389 select IRQ_DOMAIN_HIERARCHY
396 help 390 help
397 Power Domain Controller driver to manage and configure wakeup 391 Power Domain Controller driver to manage and configure wakeup
@@ -431,6 +425,27 @@ config LS1X_IRQ
431 help 425 help
432 Support for the Loongson-1 platform Interrupt Controller. 426 Support for the Loongson-1 platform Interrupt Controller.
433 427
428config TI_SCI_INTR_IRQCHIP
429 bool
430 depends on TI_SCI_PROTOCOL
431 select IRQ_DOMAIN_HIERARCHY
432 help
433 This enables the irqchip driver support for K3 Interrupt router
434 over TI System Control Interface available on some new TI's SoCs.
435 If you wish to use interrupt router irq resources managed by the
436 TI System Controller, say Y here. Otherwise, say N.
437
438config TI_SCI_INTA_IRQCHIP
439 bool
440 depends on TI_SCI_PROTOCOL
441 select IRQ_DOMAIN_HIERARCHY
442 select TI_SCI_INTA_MSI_DOMAIN
443 help
444 This enables the irqchip driver support for K3 Interrupt aggregator
445 over TI System Control Interface available on some new TI's SoCs.
446 If you wish to use interrupt aggregator irq resources managed by the
447 TI System Controller, say Y here. Otherwise, say N.
448
434endmenu 449endmenu
435 450
436config SIFIVE_PLIC 451config SIFIVE_PLIC
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index f8c66e958a64..606a003a0000 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -98,3 +98,5 @@ obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
98obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o 98obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
99obj-$(CONFIG_MADERA_IRQ) += irq-madera.o 99obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
100obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o 100obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
101obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
102obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o
diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c
index 0f6e30e9009d..0acebac1920b 100644
--- a/drivers/irqchip/irq-bcm7038-l1.c
+++ b/drivers/irqchip/irq-bcm7038-l1.c
@@ -343,6 +343,9 @@ int __init bcm7038_l1_of_init(struct device_node *dn,
343 goto out_unmap; 343 goto out_unmap;
344 } 344 }
345 345
346 pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
347 dn, IRQS_PER_WORD * intc->n_words);
348
346 return 0; 349 return 0;
347 350
348out_unmap: 351out_unmap:
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index 8968e5e93fcb..541bdca9f4af 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -318,6 +318,9 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
318 } 318 }
319 } 319 }
320 320
321 pr_info("registered %s intc (%pOF, parent IRQ(s): %d)\n",
322 intc_name, dn, data->num_parent_irqs);
323
321 return 0; 324 return 0;
322 325
323out_free_domain: 326out_free_domain:
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
index 5e4ca139e4ea..a0642b59befa 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -264,6 +264,8 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np,
264 ct->chip.irq_set_wake = irq_gc_set_wake; 264 ct->chip.irq_set_wake = irq_gc_set_wake;
265 } 265 }
266 266
267 pr_info("registered L2 intc (%pOF, parent irq: %d)\n", np, parent_irq);
268
267 return 0; 269 return 0;
268 270
269out_free_domain: 271out_free_domain:
diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c
index ecafd295c31c..c4aac0977d8a 100644
--- a/drivers/irqchip/irq-gic-pm.c
+++ b/drivers/irqchip/irq-gic-pm.c
@@ -19,7 +19,6 @@
19#include <linux/of_irq.h> 19#include <linux/of_irq.h>
20#include <linux/irqchip/arm-gic.h> 20#include <linux/irqchip/arm-gic.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include <linux/pm_clock.h>
23#include <linux/pm_runtime.h> 22#include <linux/pm_runtime.h>
24#include <linux/slab.h> 23#include <linux/slab.h>
25 24
@@ -28,17 +27,27 @@ struct gic_clk_data {
28 const char *const *clocks; 27 const char *const *clocks;
29}; 28};
30 29
30struct gic_chip_pm {
31 struct gic_chip_data *chip_data;
32 const struct gic_clk_data *clk_data;
33 struct clk_bulk_data *clks;
34};
35
31static int gic_runtime_resume(struct device *dev) 36static int gic_runtime_resume(struct device *dev)
32{ 37{
33 struct gic_chip_data *gic = dev_get_drvdata(dev); 38 struct gic_chip_pm *chip_pm = dev_get_drvdata(dev);
39 struct gic_chip_data *gic = chip_pm->chip_data;
40 const struct gic_clk_data *data = chip_pm->clk_data;
34 int ret; 41 int ret;
35 42
36 ret = pm_clk_resume(dev); 43 ret = clk_bulk_prepare_enable(data->num_clocks, chip_pm->clks);
37 if (ret) 44 if (ret) {
45 dev_err(dev, "clk_enable failed: %d\n", ret);
38 return ret; 46 return ret;
47 }
39 48
40 /* 49 /*
41 * On the very first resume, the pointer to the driver data 50 * On the very first resume, the pointer to chip_pm->chip_data
42 * will be NULL and this is intentional, because we do not 51 * will be NULL and this is intentional, because we do not
43 * want to restore the GIC on the very first resume. So if 52 * want to restore the GIC on the very first resume. So if
44 * the pointer is not valid just return. 53 * the pointer is not valid just return.
@@ -54,35 +63,14 @@ static int gic_runtime_resume(struct device *dev)
54 63
55static int gic_runtime_suspend(struct device *dev) 64static int gic_runtime_suspend(struct device *dev)
56{ 65{
57 struct gic_chip_data *gic = dev_get_drvdata(dev); 66 struct gic_chip_pm *chip_pm = dev_get_drvdata(dev);
67 struct gic_chip_data *gic = chip_pm->chip_data;
68 const struct gic_clk_data *data = chip_pm->clk_data;
58 69
59 gic_dist_save(gic); 70 gic_dist_save(gic);
60 gic_cpu_save(gic); 71 gic_cpu_save(gic);
61 72
62 return pm_clk_suspend(dev); 73 clk_bulk_disable_unprepare(data->num_clocks, chip_pm->clks);
63}
64
65static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data)
66{
67 unsigned int i;
68 int ret;
69
70 if (!dev || !data)
71 return -EINVAL;
72
73 ret = pm_clk_create(dev);
74 if (ret)
75 return ret;
76
77 for (i = 0; i < data->num_clocks; i++) {
78 ret = of_pm_clk_add_clk(dev, data->clocks[i]);
79 if (ret) {
80 dev_err(dev, "failed to add clock %s\n",
81 data->clocks[i]);
82 pm_clk_destroy(dev);
83 return ret;
84 }
85 }
86 74
87 return 0; 75 return 0;
88} 76}
@@ -91,8 +79,8 @@ static int gic_probe(struct platform_device *pdev)
91{ 79{
92 struct device *dev = &pdev->dev; 80 struct device *dev = &pdev->dev;
93 const struct gic_clk_data *data; 81 const struct gic_clk_data *data;
94 struct gic_chip_data *gic; 82 struct gic_chip_pm *chip_pm;
95 int ret, irq; 83 int ret, irq, i;
96 84
97 data = of_device_get_match_data(&pdev->dev); 85 data = of_device_get_match_data(&pdev->dev);
98 if (!data) { 86 if (!data) {
@@ -100,28 +88,41 @@ static int gic_probe(struct platform_device *pdev)
100 return -ENODEV; 88 return -ENODEV;
101 } 89 }
102 90
91 chip_pm = devm_kzalloc(dev, sizeof(*chip_pm), GFP_KERNEL);
92 if (!chip_pm)
93 return -ENOMEM;
94
103 irq = irq_of_parse_and_map(dev->of_node, 0); 95 irq = irq_of_parse_and_map(dev->of_node, 0);
104 if (!irq) { 96 if (!irq) {
105 dev_err(dev, "no parent interrupt found!\n"); 97 dev_err(dev, "no parent interrupt found!\n");
106 return -EINVAL; 98 return -EINVAL;
107 } 99 }
108 100
109 ret = gic_get_clocks(dev, data); 101 chip_pm->clks = devm_kcalloc(dev, data->num_clocks,
102 sizeof(*chip_pm->clks), GFP_KERNEL);
103 if (!chip_pm->clks)
104 return -ENOMEM;
105
106 for (i = 0; i < data->num_clocks; i++)
107 chip_pm->clks[i].id = data->clocks[i];
108
109 ret = devm_clk_bulk_get(dev, data->num_clocks, chip_pm->clks);
110 if (ret) 110 if (ret)
111 goto irq_dispose; 111 goto irq_dispose;
112 112
113 chip_pm->clk_data = data;
114 dev_set_drvdata(dev, chip_pm);
115
113 pm_runtime_enable(dev); 116 pm_runtime_enable(dev);
114 117
115 ret = pm_runtime_get_sync(dev); 118 ret = pm_runtime_get_sync(dev);
116 if (ret < 0) 119 if (ret < 0)
117 goto rpm_disable; 120 goto rpm_disable;
118 121
119 ret = gic_of_init_child(dev, &gic, irq); 122 ret = gic_of_init_child(dev, &chip_pm->chip_data, irq);
120 if (ret) 123 if (ret)
121 goto rpm_put; 124 goto rpm_put;
122 125
123 platform_set_drvdata(pdev, gic);
124
125 pm_runtime_put(dev); 126 pm_runtime_put(dev);
126 127
127 dev_info(dev, "GIC IRQ controller registered\n"); 128 dev_info(dev, "GIC IRQ controller registered\n");
@@ -132,7 +133,6 @@ rpm_put:
132 pm_runtime_put_sync(dev); 133 pm_runtime_put_sync(dev);
133rpm_disable: 134rpm_disable:
134 pm_runtime_disable(dev); 135 pm_runtime_disable(dev);
135 pm_clk_destroy(dev);
136irq_dispose: 136irq_dispose:
137 irq_dispose_mapping(irq); 137 irq_dispose_mapping(irq);
138 138
@@ -142,6 +142,8 @@ irq_dispose:
142static const struct dev_pm_ops gic_pm_ops = { 142static const struct dev_pm_ops gic_pm_ops = {
143 SET_RUNTIME_PM_OPS(gic_runtime_suspend, 143 SET_RUNTIME_PM_OPS(gic_runtime_suspend,
144 gic_runtime_resume, NULL) 144 gic_runtime_resume, NULL)
145 SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
146 pm_runtime_force_resume)
145}; 147};
146 148
147static const char * const gic400_clocks[] = { 149static const char * const gic400_clocks[] = {
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index de14e06fd9ec..3c77ab676e54 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -110,7 +110,7 @@ static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
110 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) 110 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
111 msg->data -= v2m->spi_offset; 111 msg->data -= v2m->spi_offset;
112 112
113 iommu_dma_map_msi_msg(data->irq, msg); 113 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
114} 114}
115 115
116static struct irq_chip gicv2m_irq_chip = { 116static struct irq_chip gicv2m_irq_chip = {
@@ -167,6 +167,7 @@ static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq,
167static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 167static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
168 unsigned int nr_irqs, void *args) 168 unsigned int nr_irqs, void *args)
169{ 169{
170 msi_alloc_info_t *info = args;
170 struct v2m_data *v2m = NULL, *tmp; 171 struct v2m_data *v2m = NULL, *tmp;
171 int hwirq, offset, i, err = 0; 172 int hwirq, offset, i, err = 0;
172 173
@@ -186,6 +187,11 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
186 187
187 hwirq = v2m->spi_start + offset; 188 hwirq = v2m->spi_start + offset;
188 189
190 err = iommu_dma_prepare_msi(info->desc,
191 v2m->res.start + V2M_MSI_SETSPI_NS);
192 if (err)
193 return err;
194
189 for (i = 0; i < nr_irqs; i++) { 195 for (i = 0; i < nr_irqs; i++) {
190 err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i); 196 err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
191 if (err) 197 if (err)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 128ac893d7e4..cfb9b4e5f914 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -26,7 +26,6 @@
26#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/irqdomain.h> 27#include <linux/irqdomain.h>
28#include <linux/list.h> 28#include <linux/list.h>
29#include <linux/list_sort.h>
30#include <linux/log2.h> 29#include <linux/log2.h>
31#include <linux/memblock.h> 30#include <linux/memblock.h>
32#include <linux/mm.h> 31#include <linux/mm.h>
@@ -1179,7 +1178,7 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
1179 msg->address_hi = upper_32_bits(addr); 1178 msg->address_hi = upper_32_bits(addr);
1180 msg->data = its_get_event_id(d); 1179 msg->data = its_get_event_id(d);
1181 1180
1182 iommu_dma_map_msi_msg(d->irq, msg); 1181 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(d), msg);
1183} 1182}
1184 1183
1185static int its_irq_set_irqchip_state(struct irq_data *d, 1184static int its_irq_set_irqchip_state(struct irq_data *d,
@@ -1465,9 +1464,8 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span)
1465{ 1464{
1466 struct lpi_range *range; 1465 struct lpi_range *range;
1467 1466
1468 range = kzalloc(sizeof(*range), GFP_KERNEL); 1467 range = kmalloc(sizeof(*range), GFP_KERNEL);
1469 if (range) { 1468 if (range) {
1470 INIT_LIST_HEAD(&range->entry);
1471 range->base_id = base; 1469 range->base_id = base;
1472 range->span = span; 1470 range->span = span;
1473 } 1471 }
@@ -1475,31 +1473,6 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span)
1475 return range; 1473 return range;
1476} 1474}
1477 1475
1478static int lpi_range_cmp(void *priv, struct list_head *a, struct list_head *b)
1479{
1480 struct lpi_range *ra, *rb;
1481
1482 ra = container_of(a, struct lpi_range, entry);
1483 rb = container_of(b, struct lpi_range, entry);
1484
1485 return ra->base_id - rb->base_id;
1486}
1487
1488static void merge_lpi_ranges(void)
1489{
1490 struct lpi_range *range, *tmp;
1491
1492 list_for_each_entry_safe(range, tmp, &lpi_range_list, entry) {
1493 if (!list_is_last(&range->entry, &lpi_range_list) &&
1494 (tmp->base_id == (range->base_id + range->span))) {
1495 tmp->base_id = range->base_id;
1496 tmp->span += range->span;
1497 list_del(&range->entry);
1498 kfree(range);
1499 }
1500 }
1501}
1502
1503static int alloc_lpi_range(u32 nr_lpis, u32 *base) 1476static int alloc_lpi_range(u32 nr_lpis, u32 *base)
1504{ 1477{
1505 struct lpi_range *range, *tmp; 1478 struct lpi_range *range, *tmp;
@@ -1529,25 +1502,49 @@ static int alloc_lpi_range(u32 nr_lpis, u32 *base)
1529 return err; 1502 return err;
1530} 1503}
1531 1504
1505static void merge_lpi_ranges(struct lpi_range *a, struct lpi_range *b)
1506{
1507 if (&a->entry == &lpi_range_list || &b->entry == &lpi_range_list)
1508 return;
1509 if (a->base_id + a->span != b->base_id)
1510 return;
1511 b->base_id = a->base_id;
1512 b->span += a->span;
1513 list_del(&a->entry);
1514 kfree(a);
1515}
1516
1532static int free_lpi_range(u32 base, u32 nr_lpis) 1517static int free_lpi_range(u32 base, u32 nr_lpis)
1533{ 1518{
1534 struct lpi_range *new; 1519 struct lpi_range *new, *old;
1535 int err = 0; 1520
1521 new = mk_lpi_range(base, nr_lpis);
1522 if (!new)
1523 return -ENOMEM;
1536 1524
1537 mutex_lock(&lpi_range_lock); 1525 mutex_lock(&lpi_range_lock);
1538 1526
1539 new = mk_lpi_range(base, nr_lpis); 1527 list_for_each_entry_reverse(old, &lpi_range_list, entry) {
1540 if (!new) { 1528 if (old->base_id < base)
1541 err = -ENOMEM; 1529 break;
1542 goto out;
1543 } 1530 }
1531 /*
1532 * old is the last element with ->base_id smaller than base,
1533 * so new goes right after it. If there are no elements with
1534 * ->base_id smaller than base, &old->entry ends up pointing
1535 * at the head of the list, and inserting new it the start of
1536 * the list is the right thing to do in that case as well.
1537 */
1538 list_add(&new->entry, &old->entry);
1539 /*
1540 * Now check if we can merge with the preceding and/or
1541 * following ranges.
1542 */
1543 merge_lpi_ranges(old, new);
1544 merge_lpi_ranges(new, list_next_entry(new, entry));
1544 1545
1545 list_add(&new->entry, &lpi_range_list);
1546 list_sort(NULL, &lpi_range_list, lpi_range_cmp);
1547 merge_lpi_ranges();
1548out:
1549 mutex_unlock(&lpi_range_lock); 1546 mutex_unlock(&lpi_range_lock);
1550 return err; 1547 return 0;
1551} 1548}
1552 1549
1553static int __init its_lpi_init(u32 id_bits) 1550static int __init its_lpi_init(u32 id_bits)
@@ -2487,7 +2484,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
2487 int err = 0; 2484 int err = 0;
2488 2485
2489 /* 2486 /*
2490 * We ignore "dev" entierely, and rely on the dev_id that has 2487 * We ignore "dev" entirely, and rely on the dev_id that has
2491 * been passed via the scratchpad. This limits this domain's 2488 * been passed via the scratchpad. This limits this domain's
2492 * usefulness to upper layers that definitely know that they 2489 * usefulness to upper layers that definitely know that they
2493 * are built on top of the ITS. 2490 * are built on top of the ITS.
@@ -2566,6 +2563,7 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
2566{ 2563{
2567 msi_alloc_info_t *info = args; 2564 msi_alloc_info_t *info = args;
2568 struct its_device *its_dev = info->scratchpad[0].ptr; 2565 struct its_device *its_dev = info->scratchpad[0].ptr;
2566 struct its_node *its = its_dev->its;
2569 irq_hw_number_t hwirq; 2567 irq_hw_number_t hwirq;
2570 int err; 2568 int err;
2571 int i; 2569 int i;
@@ -2574,6 +2572,10 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
2574 if (err) 2572 if (err)
2575 return err; 2573 return err;
2576 2574
2575 err = iommu_dma_prepare_msi(info->desc, its->get_msi_base(its_dev));
2576 if (err)
2577 return err;
2578
2577 for (i = 0; i < nr_irqs; i++) { 2579 for (i = 0; i < nr_irqs; i++) {
2578 err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i); 2580 err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
2579 if (err) 2581 if (err)
diff --git a/drivers/irqchip/irq-gic-v3-mbi.c b/drivers/irqchip/irq-gic-v3-mbi.c
index fbfa7ff6deb1..563a9b366294 100644
--- a/drivers/irqchip/irq-gic-v3-mbi.c
+++ b/drivers/irqchip/irq-gic-v3-mbi.c
@@ -84,6 +84,7 @@ static void mbi_free_msi(struct mbi_range *mbi, unsigned int hwirq,
84static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 84static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
85 unsigned int nr_irqs, void *args) 85 unsigned int nr_irqs, void *args)
86{ 86{
87 msi_alloc_info_t *info = args;
87 struct mbi_range *mbi = NULL; 88 struct mbi_range *mbi = NULL;
88 int hwirq, offset, i, err = 0; 89 int hwirq, offset, i, err = 0;
89 90
@@ -104,6 +105,11 @@ static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
104 105
105 hwirq = mbi->spi_start + offset; 106 hwirq = mbi->spi_start + offset;
106 107
108 err = iommu_dma_prepare_msi(info->desc,
109 mbi_phys_base + GICD_SETSPI_NSR);
110 if (err)
111 return err;
112
107 for (i = 0; i < nr_irqs; i++) { 113 for (i = 0; i < nr_irqs; i++) {
108 err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i); 114 err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
109 if (err) 115 if (err)
@@ -142,7 +148,7 @@ static void mbi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
142 msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR); 148 msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR);
143 msg[0].data = data->parent_data->hwirq; 149 msg[0].data = data->parent_data->hwirq;
144 150
145 iommu_dma_map_msi_msg(data->irq, msg); 151 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
146} 152}
147 153
148#ifdef CONFIG_PCI_MSI 154#ifdef CONFIG_PCI_MSI
@@ -202,7 +208,7 @@ static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg)
202 msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR); 208 msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR);
203 msg[1].data = data->parent_data->hwirq; 209 msg[1].data = data->parent_data->hwirq;
204 210
205 iommu_dma_map_msi_msg(data->irq, &msg[1]); 211 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), &msg[1]);
206} 212}
207 213
208/* Platform-MSI specific irqchip */ 214/* Platform-MSI specific irqchip */
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
index 88df3d00052c..290531ec3d61 100644
--- a/drivers/irqchip/irq-imx-irqsteer.c
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -144,7 +144,6 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
144{ 144{
145 struct device_node *np = pdev->dev.of_node; 145 struct device_node *np = pdev->dev.of_node;
146 struct irqsteer_data *data; 146 struct irqsteer_data *data;
147 struct resource *res;
148 u32 irqs_num; 147 u32 irqs_num;
149 int i, ret; 148 int i, ret;
150 149
@@ -152,8 +151,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
152 if (!data) 151 if (!data)
153 return -ENOMEM; 152 return -ENOMEM;
154 153
155 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 154 data->regs = devm_platform_ioremap_resource(pdev, 0);
156 data->regs = devm_ioremap_resource(&pdev->dev, res);
157 if (IS_ERR(data->regs)) { 155 if (IS_ERR(data->regs)) {
158 dev_err(&pdev->dev, "failed to initialize reg\n"); 156 dev_err(&pdev->dev, "failed to initialize reg\n");
159 return PTR_ERR(data->regs); 157 return PTR_ERR(data->regs);
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index c671b3212010..669d29105772 100644
--- a/drivers/irqchip/irq-ls-scfg-msi.c
+++ b/drivers/irqchip/irq-ls-scfg-msi.c
@@ -100,7 +100,7 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
100 msg->data |= cpumask_first(mask); 100 msg->data |= cpumask_first(mask);
101 } 101 }
102 102
103 iommu_dma_map_msi_msg(data->irq, msg); 103 iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
104} 104}
105 105
106static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, 106static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
@@ -141,6 +141,7 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain,
141 unsigned int nr_irqs, 141 unsigned int nr_irqs,
142 void *args) 142 void *args)
143{ 143{
144 msi_alloc_info_t *info = args;
144 struct ls_scfg_msi *msi_data = domain->host_data; 145 struct ls_scfg_msi *msi_data = domain->host_data;
145 int pos, err = 0; 146 int pos, err = 0;
146 147
@@ -157,6 +158,10 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain,
157 if (err) 158 if (err)
158 return err; 159 return err;
159 160
161 err = iommu_dma_prepare_msi(info->desc, msi_data->msiir_addr);
162 if (err)
163 return err;
164
160 irq_domain_set_info(domain, virq, pos, 165 irq_domain_set_info(domain, virq, pos,
161 &ls_scfg_msi_parent_chip, msi_data, 166 &ls_scfg_msi_parent_chip, msi_data,
162 handle_simple_irq, NULL, NULL); 167 handle_simple_irq, NULL, NULL);
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 8c039525703f..04c05a18600c 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -389,10 +389,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
389 int k; 389 int k;
390 390
391 p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); 391 p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
392 if (!p) { 392 if (!p)
393 dev_err(dev, "failed to allocate driver data\n");
394 return -ENOMEM; 393 return -ENOMEM;
395 }
396 394
397 /* deal with driver instance configuration */ 395 /* deal with driver instance configuration */
398 of_property_read_u32(dev->of_node, "sense-bitfield-width", 396 of_property_read_u32(dev->of_node, "sense-bitfield-width",
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 7bd1d4cb2e19..e00f2fa27f00 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -14,8 +14,10 @@
14#include <linux/irqchip.h> 14#include <linux/irqchip.h>
15#include <linux/irqchip/chained_irq.h> 15#include <linux/irqchip/chained_irq.h>
16#include <linux/irqdomain.h> 16#include <linux/irqdomain.h>
17#include <linux/module.h>
17#include <linux/of_address.h> 18#include <linux/of_address.h>
18#include <linux/of_irq.h> 19#include <linux/of_irq.h>
20#include <linux/of_platform.h>
19#include <linux/syscore_ops.h> 21#include <linux/syscore_ops.h>
20 22
21#include <dt-bindings/interrupt-controller/arm-gic.h> 23#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -37,12 +39,6 @@ struct stm32_exti_bank {
37 39
38#define UNDEF_REG ~0 40#define UNDEF_REG ~0
39 41
40enum stm32_exti_hwspinlock {
41 HWSPINLOCK_UNKNOWN,
42 HWSPINLOCK_NONE,
43 HWSPINLOCK_READY,
44};
45
46struct stm32_desc_irq { 42struct stm32_desc_irq {
47 u32 exti; 43 u32 exti;
48 u32 irq_parent; 44 u32 irq_parent;
@@ -69,8 +65,6 @@ struct stm32_exti_host_data {
69 void __iomem *base; 65 void __iomem *base;
70 struct stm32_exti_chip_data *chips_data; 66 struct stm32_exti_chip_data *chips_data;
71 const struct stm32_exti_drv_data *drv_data; 67 const struct stm32_exti_drv_data *drv_data;
72 struct device_node *node;
73 enum stm32_exti_hwspinlock hwlock_state;
74 struct hwspinlock *hwlock; 68 struct hwspinlock *hwlock;
75}; 69};
76 70
@@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d,
285 279
286static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) 280static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
287{ 281{
288 struct stm32_exti_host_data *host_data = chip_data->host_data; 282 int ret, timeout = 0;
289 struct hwspinlock *hwlock;
290 int id, ret = 0, timeout = 0;
291
292 /* first time, check for hwspinlock availability */
293 if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
294 id = of_hwspin_lock_get_id(host_data->node, 0);
295 if (id >= 0) {
296 hwlock = hwspin_lock_request_specific(id);
297 if (hwlock) {
298 /* found valid hwspinlock */
299 host_data->hwlock_state = HWSPINLOCK_READY;
300 host_data->hwlock = hwlock;
301 pr_debug("%s hwspinlock = %d\n", __func__, id);
302 } else {
303 host_data->hwlock_state = HWSPINLOCK_NONE;
304 }
305 } else if (id != -EPROBE_DEFER) {
306 host_data->hwlock_state = HWSPINLOCK_NONE;
307 } else {
308 /* hwspinlock driver shall be ready at that stage */
309 ret = -EPROBE_DEFER;
310 }
311 }
312 283
313 if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) { 284 if (!chip_data->host_data->hwlock)
314 /* 285 return 0;
315 * Use the x_raw API since we are under spin_lock protection. 286
316 * Do not use the x_timeout API because we are under irq_disable 287 /*
317 * mode (see __setup_irq()) 288 * Use the x_raw API since we are under spin_lock protection.
318 */ 289 * Do not use the x_timeout API because we are under irq_disable
319 do { 290 * mode (see __setup_irq())
320 ret = hwspin_trylock_raw(host_data->hwlock); 291 */
321 if (!ret) 292 do {
322 return 0; 293 ret = hwspin_trylock_raw(chip_data->host_data->hwlock);
323 294 if (!ret)
324 udelay(HWSPNLCK_RETRY_DELAY); 295 return 0;
325 timeout += HWSPNLCK_RETRY_DELAY; 296
326 } while (timeout < HWSPNLCK_TIMEOUT); 297 udelay(HWSPNLCK_RETRY_DELAY);
327 298 timeout += HWSPNLCK_RETRY_DELAY;
328 if (ret == -EBUSY) 299 } while (timeout < HWSPNLCK_TIMEOUT);
329 ret = -ETIMEDOUT; 300
330 } 301 if (ret == -EBUSY)
302 ret = -ETIMEDOUT;
331 303
332 if (ret) 304 if (ret)
333 pr_err("%s can't get hwspinlock (%d)\n", __func__, ret); 305 pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
@@ -337,7 +309,7 @@ static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
337 309
338static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data) 310static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
339{ 311{
340 if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY)) 312 if (chip_data->host_data->hwlock)
341 hwspin_unlock_raw(chip_data->host_data->hwlock); 313 hwspin_unlock_raw(chip_data->host_data->hwlock);
342} 314}
343 315
@@ -586,8 +558,7 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
586 return -EINVAL; 558 return -EINVAL;
587} 559}
588 560
589#ifdef CONFIG_PM 561static int __maybe_unused stm32_exti_h_suspend(void)
590static int stm32_exti_h_suspend(void)
591{ 562{
592 struct stm32_exti_chip_data *chip_data; 563 struct stm32_exti_chip_data *chip_data;
593 int i; 564 int i;
@@ -602,7 +573,7 @@ static int stm32_exti_h_suspend(void)
602 return 0; 573 return 0;
603} 574}
604 575
605static void stm32_exti_h_resume(void) 576static void __maybe_unused stm32_exti_h_resume(void)
606{ 577{
607 struct stm32_exti_chip_data *chip_data; 578 struct stm32_exti_chip_data *chip_data;
608 int i; 579 int i;
@@ -616,17 +587,22 @@ static void stm32_exti_h_resume(void)
616} 587}
617 588
618static struct syscore_ops stm32_exti_h_syscore_ops = { 589static struct syscore_ops stm32_exti_h_syscore_ops = {
590#ifdef CONFIG_PM_SLEEP
619 .suspend = stm32_exti_h_suspend, 591 .suspend = stm32_exti_h_suspend,
620 .resume = stm32_exti_h_resume, 592 .resume = stm32_exti_h_resume,
593#endif
621}; 594};
622 595
623static void stm32_exti_h_syscore_init(void) 596static void stm32_exti_h_syscore_init(struct stm32_exti_host_data *host_data)
624{ 597{
598 stm32_host_data = host_data;
625 register_syscore_ops(&stm32_exti_h_syscore_ops); 599 register_syscore_ops(&stm32_exti_h_syscore_ops);
626} 600}
627#else 601
628static inline void stm32_exti_h_syscore_init(void) {} 602static void stm32_exti_h_syscore_deinit(void)
629#endif 603{
604 unregister_syscore_ops(&stm32_exti_h_syscore_ops);
605}
630 606
631static struct irq_chip stm32_exti_h_chip = { 607static struct irq_chip stm32_exti_h_chip = {
632 .name = "stm32-exti-h", 608 .name = "stm32-exti-h",
@@ -683,8 +659,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
683 return NULL; 659 return NULL;
684 660
685 host_data->drv_data = dd; 661 host_data->drv_data = dd;
686 host_data->node = node;
687 host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
688 host_data->chips_data = kcalloc(dd->bank_nr, 662 host_data->chips_data = kcalloc(dd->bank_nr,
689 sizeof(struct stm32_exti_chip_data), 663 sizeof(struct stm32_exti_chip_data),
690 GFP_KERNEL); 664 GFP_KERNEL);
@@ -711,7 +685,8 @@ free_host_data:
711 685
712static struct 686static struct
713stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, 687stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
714 u32 bank_idx) 688 u32 bank_idx,
689 struct device_node *node)
715{ 690{
716 const struct stm32_exti_bank *stm32_bank; 691 const struct stm32_exti_bank *stm32_bank;
717 struct stm32_exti_chip_data *chip_data; 692 struct stm32_exti_chip_data *chip_data;
@@ -731,7 +706,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
731 writel_relaxed(0, base + stm32_bank->imr_ofst); 706 writel_relaxed(0, base + stm32_bank->imr_ofst);
732 writel_relaxed(0, base + stm32_bank->emr_ofst); 707 writel_relaxed(0, base + stm32_bank->emr_ofst);
733 708
734 pr_info("%pOF: bank%d\n", h_data->node, bank_idx); 709 pr_info("%pOF: bank%d\n", node, bank_idx);
735 710
736 return chip_data; 711 return chip_data;
737} 712}
@@ -771,7 +746,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
771 struct stm32_exti_chip_data *chip_data; 746 struct stm32_exti_chip_data *chip_data;
772 747
773 stm32_bank = drv_data->exti_banks[i]; 748 stm32_bank = drv_data->exti_banks[i];
774 chip_data = stm32_exti_chip_init(host_data, i); 749 chip_data = stm32_exti_chip_init(host_data, i, node);
775 750
776 gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); 751 gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
777 752
@@ -815,50 +790,130 @@ static const struct irq_domain_ops stm32_exti_h_domain_ops = {
815 .xlate = irq_domain_xlate_twocell, 790 .xlate = irq_domain_xlate_twocell,
816}; 791};
817 792
818static int 793static void stm32_exti_remove_irq(void *data)
819__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, 794{
820 struct device_node *node, 795 struct irq_domain *domain = data;
821 struct device_node *parent) 796
797 irq_domain_remove(domain);
798}
799
800static int stm32_exti_remove(struct platform_device *pdev)
801{
802 stm32_exti_h_syscore_deinit();
803 return 0;
804}
805
806static int stm32_exti_probe(struct platform_device *pdev)
822{ 807{
808 int ret, i;
809 struct device *dev = &pdev->dev;
810 struct device_node *np = dev->of_node;
823 struct irq_domain *parent_domain, *domain; 811 struct irq_domain *parent_domain, *domain;
824 struct stm32_exti_host_data *host_data; 812 struct stm32_exti_host_data *host_data;
825 int ret, i; 813 const struct stm32_exti_drv_data *drv_data;
814 struct resource *res;
826 815
827 parent_domain = irq_find_host(parent); 816 host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
828 if (!parent_domain) { 817 if (!host_data)
829 pr_err("interrupt-parent not found\n"); 818 return -ENOMEM;
830 return -EINVAL; 819
820 /* check for optional hwspinlock which may be not available yet */
821 ret = of_hwspin_lock_get_id(np, 0);
822 if (ret == -EPROBE_DEFER)
823 /* hwspinlock framework not yet ready */
824 return ret;
825
826 if (ret >= 0) {
827 host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
828 if (!host_data->hwlock) {
829 dev_err(dev, "Failed to request hwspinlock\n");
830 return -EINVAL;
831 }
832 } else if (ret != -ENOENT) {
833 /* note: ENOENT is a valid case (means 'no hwspinlock') */
834 dev_err(dev, "Failed to get hwspinlock\n");
835 return ret;
831 } 836 }
832 837
833 host_data = stm32_exti_host_init(drv_data, node); 838 /* initialize host_data */
834 if (!host_data) 839 drv_data = of_device_get_match_data(dev);
840 if (!drv_data) {
841 dev_err(dev, "no of match data\n");
842 return -ENODEV;
843 }
844 host_data->drv_data = drv_data;
845
846 host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr,
847 sizeof(*host_data->chips_data),
848 GFP_KERNEL);
849 if (!host_data->chips_data)
835 return -ENOMEM; 850 return -ENOMEM;
836 851
852 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
853 host_data->base = devm_ioremap_resource(dev, res);
854 if (IS_ERR(host_data->base)) {
855 dev_err(dev, "Unable to map registers\n");
856 return PTR_ERR(host_data->base);
857 }
858
837 for (i = 0; i < drv_data->bank_nr; i++) 859 for (i = 0; i < drv_data->bank_nr; i++)
838 stm32_exti_chip_init(host_data, i); 860 stm32_exti_chip_init(host_data, i, np);
861
862 parent_domain = irq_find_host(of_irq_find_parent(np));
863 if (!parent_domain) {
864 dev_err(dev, "GIC interrupt-parent not found\n");
865 return -EINVAL;
866 }
839 867
840 domain = irq_domain_add_hierarchy(parent_domain, 0, 868 domain = irq_domain_add_hierarchy(parent_domain, 0,
841 drv_data->bank_nr * IRQS_PER_BANK, 869 drv_data->bank_nr * IRQS_PER_BANK,
842 node, &stm32_exti_h_domain_ops, 870 np, &stm32_exti_h_domain_ops,
843 host_data); 871 host_data);
844 872
845 if (!domain) { 873 if (!domain) {
846 pr_err("%pOFn: Could not register exti domain.\n", node); 874 dev_err(dev, "Could not register exti domain\n");
847 ret = -ENOMEM; 875 return -ENOMEM;
848 goto out_unmap;
849 } 876 }
850 877
851 stm32_exti_h_syscore_init(); 878 ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, domain);
879 if (ret)
880 return ret;
881
882 stm32_exti_h_syscore_init(host_data);
852 883
853 return 0; 884 return 0;
885}
854 886
855out_unmap: 887/* platform driver only for MP1 */
856 iounmap(host_data->base); 888static const struct of_device_id stm32_exti_ids[] = {
857 kfree(host_data->chips_data); 889 { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data},
858 kfree(host_data); 890 {},
859 return ret; 891};
892MODULE_DEVICE_TABLE(of, stm32_exti_ids);
893
894static struct platform_driver stm32_exti_driver = {
895 .probe = stm32_exti_probe,
896 .remove = stm32_exti_remove,
897 .driver = {
898 .name = "stm32_exti",
899 .of_match_table = stm32_exti_ids,
900 },
901};
902
903static int __init stm32_exti_arch_init(void)
904{
905 return platform_driver_register(&stm32_exti_driver);
860} 906}
861 907
908static void __exit stm32_exti_arch_exit(void)
909{
910 return platform_driver_unregister(&stm32_exti_driver);
911}
912
913arch_initcall(stm32_exti_arch_init);
914module_exit(stm32_exti_arch_exit);
915
916/* no platform driver for F4 and H7 */
862static int __init stm32f4_exti_of_init(struct device_node *np, 917static int __init stm32f4_exti_of_init(struct device_node *np,
863 struct device_node *parent) 918 struct device_node *parent)
864{ 919{
@@ -874,11 +929,3 @@ static int __init stm32h7_exti_of_init(struct device_node *np,
874} 929}
875 930
876IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); 931IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
877
878static int __init stm32mp1_exti_of_init(struct device_node *np,
879 struct device_node *parent)
880{
881 return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
882}
883
884IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
new file mode 100644
index 000000000000..011b60a49e3f
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -0,0 +1,615 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments' K3 Interrupt Aggregator irqchip driver
4 *
5 * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Lokesh Vutla <lokeshvutla@ti.com>
7 */
8
9#include <linux/err.h>
10#include <linux/io.h>
11#include <linux/irqchip.h>
12#include <linux/irqdomain.h>
13#include <linux/interrupt.h>
14#include <linux/msi.h>
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/of_address.h>
18#include <linux/of_irq.h>
19#include <linux/of_platform.h>
20#include <linux/irqchip/chained_irq.h>
21#include <linux/soc/ti/ti_sci_inta_msi.h>
22#include <linux/soc/ti/ti_sci_protocol.h>
23#include <asm-generic/msi.h>
24
25#define TI_SCI_DEV_ID_MASK 0xffff
26#define TI_SCI_DEV_ID_SHIFT 16
27#define TI_SCI_IRQ_ID_MASK 0xffff
28#define TI_SCI_IRQ_ID_SHIFT 0
29#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
30 (TI_SCI_DEV_ID_MASK))
31#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
32#define TO_HWIRQ(dev, index) ((((dev) & TI_SCI_DEV_ID_MASK) << \
33 TI_SCI_DEV_ID_SHIFT) | \
34 ((index) & TI_SCI_IRQ_ID_MASK))
35
36#define MAX_EVENTS_PER_VINT 64
37#define VINT_ENABLE_SET_OFFSET 0x0
38#define VINT_ENABLE_CLR_OFFSET 0x8
39#define VINT_STATUS_OFFSET 0x18
40
41/**
42 * struct ti_sci_inta_event_desc - Description of an event coming to
43 * Interrupt Aggregator. This serves
44 * as a mapping table for global event,
45 * hwirq and vint bit.
46 * @global_event: Global event number corresponding to this event
47 * @hwirq: Hwirq of the incoming interrupt
48 * @vint_bit: Corresponding vint bit to which this event is attached.
49 */
50struct ti_sci_inta_event_desc {
51 u16 global_event;
52 u32 hwirq;
53 u8 vint_bit;
54};
55
56/**
57 * struct ti_sci_inta_vint_desc - Description of a virtual interrupt coming out
58 * of Interrupt Aggregator.
59 * @domain: Pointer to IRQ domain to which this vint belongs.
60 * @list: List entry for the vint list
61 * @event_map: Bitmap to manage the allocation of events to vint.
62 * @events: Array of event descriptors assigned to this vint.
63 * @parent_virq: Linux IRQ number that gets attached to parent
64 * @vint_id: TISCI vint ID
65 */
66struct ti_sci_inta_vint_desc {
67 struct irq_domain *domain;
68 struct list_head list;
69 DECLARE_BITMAP(event_map, MAX_EVENTS_PER_VINT);
70 struct ti_sci_inta_event_desc events[MAX_EVENTS_PER_VINT];
71 unsigned int parent_virq;
72 u16 vint_id;
73};
74
75/**
76 * struct ti_sci_inta_irq_domain - Structure representing a TISCI based
77 * Interrupt Aggregator IRQ domain.
78 * @sci: Pointer to TISCI handle
79 * @vint: TISCI resource pointer representing IA inerrupts.
80 * @global_event: TISCI resource pointer representing global events.
81 * @vint_list: List of the vints active in the system
82 * @vint_mutex: Mutex to protect vint_list
83 * @base: Base address of the memory mapped IO registers
84 * @pdev: Pointer to platform device.
85 */
86struct ti_sci_inta_irq_domain {
87 const struct ti_sci_handle *sci;
88 struct ti_sci_resource *vint;
89 struct ti_sci_resource *global_event;
90 struct list_head vint_list;
91 /* Mutex to protect vint list */
92 struct mutex vint_mutex;
93 void __iomem *base;
94 struct platform_device *pdev;
95};
96
97#define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
98 events[i])
99
100/**
101 * ti_sci_inta_irq_handler() - Chained IRQ handler for the vint irqs
102 * @desc: Pointer to irq_desc corresponding to the irq
103 */
104static void ti_sci_inta_irq_handler(struct irq_desc *desc)
105{
106 struct ti_sci_inta_vint_desc *vint_desc;
107 struct ti_sci_inta_irq_domain *inta;
108 struct irq_domain *domain;
109 unsigned int virq, bit;
110 unsigned long val;
111
112 vint_desc = irq_desc_get_handler_data(desc);
113 domain = vint_desc->domain;
114 inta = domain->host_data;
115
116 chained_irq_enter(irq_desc_get_chip(desc), desc);
117
118 val = readq_relaxed(inta->base + vint_desc->vint_id * 0x1000 +
119 VINT_STATUS_OFFSET);
120
121 for_each_set_bit(bit, &val, MAX_EVENTS_PER_VINT) {
122 virq = irq_find_mapping(domain, vint_desc->events[bit].hwirq);
123 if (virq)
124 generic_handle_irq(virq);
125 }
126
127 chained_irq_exit(irq_desc_get_chip(desc), desc);
128}
129
130/**
131 * ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
132 * @domain: IRQ domain corresponding to Interrupt Aggregator
133 *
134 * Return 0 if all went well else corresponding error value.
135 */
136static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_domain *domain)
137{
138 struct ti_sci_inta_irq_domain *inta = domain->host_data;
139 struct ti_sci_inta_vint_desc *vint_desc;
140 struct irq_fwspec parent_fwspec;
141 unsigned int parent_virq;
142 u16 vint_id;
143
144 vint_id = ti_sci_get_free_resource(inta->vint);
145 if (vint_id == TI_SCI_RESOURCE_NULL)
146 return ERR_PTR(-EINVAL);
147
148 vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
149 if (!vint_desc)
150 return ERR_PTR(-ENOMEM);
151
152 vint_desc->domain = domain;
153 vint_desc->vint_id = vint_id;
154 INIT_LIST_HEAD(&vint_desc->list);
155
156 parent_fwspec.fwnode = of_node_to_fwnode(of_irq_find_parent(dev_of_node(&inta->pdev->dev)));
157 parent_fwspec.param_count = 2;
158 parent_fwspec.param[0] = inta->pdev->id;
159 parent_fwspec.param[1] = vint_desc->vint_id;
160
161 parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
162 if (parent_virq <= 0) {
163 kfree(vint_desc);
164 return ERR_PTR(parent_virq);
165 }
166 vint_desc->parent_virq = parent_virq;
167
168 list_add_tail(&vint_desc->list, &inta->vint_list);
169 irq_set_chained_handler_and_data(vint_desc->parent_virq,
170 ti_sci_inta_irq_handler, vint_desc);
171
172 return vint_desc;
173}
174
175/**
176 * ti_sci_inta_alloc_event() - Attach an event to a IA vint.
177 * @vint_desc: Pointer to vint_desc to which the event gets attached
178 * @free_bit: Bit inside vint to which event gets attached
179 * @hwirq: hwirq of the input event
180 *
181 * Return event_desc pointer if all went ok else appropriate error value.
182 */
183static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta_vint_desc *vint_desc,
184 u16 free_bit,
185 u32 hwirq)
186{
187 struct ti_sci_inta_irq_domain *inta = vint_desc->domain->host_data;
188 struct ti_sci_inta_event_desc *event_desc;
189 u16 dev_id, dev_index;
190 int err;
191
192 dev_id = HWIRQ_TO_DEVID(hwirq);
193 dev_index = HWIRQ_TO_IRQID(hwirq);
194
195 event_desc = &vint_desc->events[free_bit];
196 event_desc->hwirq = hwirq;
197 event_desc->vint_bit = free_bit;
198 event_desc->global_event = ti_sci_get_free_resource(inta->global_event);
199 if (event_desc->global_event == TI_SCI_RESOURCE_NULL)
200 return ERR_PTR(-EINVAL);
201
202 err = inta->sci->ops.rm_irq_ops.set_event_map(inta->sci,
203 dev_id, dev_index,
204 inta->pdev->id,
205 vint_desc->vint_id,
206 event_desc->global_event,
207 free_bit);
208 if (err)
209 goto free_global_event;
210
211 return event_desc;
212free_global_event:
213 ti_sci_release_resource(inta->global_event, event_desc->global_event);
214 return ERR_PTR(err);
215}
216
217/**
218 * ti_sci_inta_alloc_irq() - Allocate an irq within INTA domain
219 * @domain: irq_domain pointer corresponding to INTA
220 * @hwirq: hwirq of the input event
221 *
222 * Note: Allocation happens in the following manner:
223 * - Find a free bit available in any of the vints available in the list.
224 * - If not found, allocate a vint from the vint pool
225 * - Attach the free bit to input hwirq.
226 * Return event_desc if all went ok else appropriate error value.
227 */
228static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_irq(struct irq_domain *domain,
229 u32 hwirq)
230{
231 struct ti_sci_inta_irq_domain *inta = domain->host_data;
232 struct ti_sci_inta_vint_desc *vint_desc = NULL;
233 struct ti_sci_inta_event_desc *event_desc;
234 u16 free_bit;
235
236 mutex_lock(&inta->vint_mutex);
237 list_for_each_entry(vint_desc, &inta->vint_list, list) {
238 free_bit = find_first_zero_bit(vint_desc->event_map,
239 MAX_EVENTS_PER_VINT);
240 if (free_bit != MAX_EVENTS_PER_VINT) {
241 set_bit(free_bit, vint_desc->event_map);
242 goto alloc_event;
243 }
244 }
245
246 /* No free bits available. Allocate a new vint */
247 vint_desc = ti_sci_inta_alloc_parent_irq(domain);
248 if (IS_ERR(vint_desc)) {
249 mutex_unlock(&inta->vint_mutex);
250 return ERR_PTR(PTR_ERR(vint_desc));
251 }
252
253 free_bit = find_first_zero_bit(vint_desc->event_map,
254 MAX_EVENTS_PER_VINT);
255 set_bit(free_bit, vint_desc->event_map);
256
257alloc_event:
258 event_desc = ti_sci_inta_alloc_event(vint_desc, free_bit, hwirq);
259 if (IS_ERR(event_desc))
260 clear_bit(free_bit, vint_desc->event_map);
261
262 mutex_unlock(&inta->vint_mutex);
263 return event_desc;
264}
265
266/**
267 * ti_sci_inta_free_parent_irq() - Free a parent irq to INTA
268 * @inta: Pointer to inta domain.
269 * @vint_desc: Pointer to vint_desc that needs to be freed.
270 */
271static void ti_sci_inta_free_parent_irq(struct ti_sci_inta_irq_domain *inta,
272 struct ti_sci_inta_vint_desc *vint_desc)
273{
274 if (find_first_bit(vint_desc->event_map, MAX_EVENTS_PER_VINT) == MAX_EVENTS_PER_VINT) {
275 list_del(&vint_desc->list);
276 ti_sci_release_resource(inta->vint, vint_desc->vint_id);
277 irq_dispose_mapping(vint_desc->parent_virq);
278 kfree(vint_desc);
279 }
280}
281
282/**
283 * ti_sci_inta_free_irq() - Free an IRQ within INTA domain
284 * @event_desc: Pointer to event_desc that needs to be freed.
285 * @hwirq: Hwirq number within INTA domain that needs to be freed
286 */
287static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
288 u32 hwirq)
289{
290 struct ti_sci_inta_vint_desc *vint_desc;
291 struct ti_sci_inta_irq_domain *inta;
292
293 vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
294 inta = vint_desc->domain->host_data;
295 /* free event irq */
296 mutex_lock(&inta->vint_mutex);
297 inta->sci->ops.rm_irq_ops.free_event_map(inta->sci,
298 HWIRQ_TO_DEVID(hwirq),
299 HWIRQ_TO_IRQID(hwirq),
300 inta->pdev->id,
301 vint_desc->vint_id,
302 event_desc->global_event,
303 event_desc->vint_bit);
304
305 clear_bit(event_desc->vint_bit, vint_desc->event_map);
306 ti_sci_release_resource(inta->global_event, event_desc->global_event);
307 event_desc->global_event = TI_SCI_RESOURCE_NULL;
308 event_desc->hwirq = 0;
309
310 ti_sci_inta_free_parent_irq(inta, vint_desc);
311 mutex_unlock(&inta->vint_mutex);
312}
313
314/**
315 * ti_sci_inta_request_resources() - Allocate resources for input irq
316 * @data: Pointer to corresponding irq_data
317 *
318 * Note: This is the core api where the actual allocation happens for input
319 * hwirq. This allocation involves creating a parent irq for vint.
320 * If this is done in irq_domain_ops.alloc() then a deadlock is reached
321 * for allocation. So this allocation is being done in request_resources()
322 *
323 * Return: 0 if all went well else corresponding error.
324 */
325static int ti_sci_inta_request_resources(struct irq_data *data)
326{
327 struct ti_sci_inta_event_desc *event_desc;
328
329 event_desc = ti_sci_inta_alloc_irq(data->domain, data->hwirq);
330 if (IS_ERR(event_desc))
331 return PTR_ERR(event_desc);
332
333 data->chip_data = event_desc;
334
335 return 0;
336}
337
338/**
339 * ti_sci_inta_release_resources - Release resources for input irq
340 * @data: Pointer to corresponding irq_data
341 *
342 * Note: Corresponding to request_resources(), all the unmapping and deletion
343 * of parent vint irqs happens in this api.
344 */
345static void ti_sci_inta_release_resources(struct irq_data *data)
346{
347 struct ti_sci_inta_event_desc *event_desc;
348
349 event_desc = irq_data_get_irq_chip_data(data);
350 ti_sci_inta_free_irq(event_desc, data->hwirq);
351}
352
353/**
354 * ti_sci_inta_manage_event() - Control the event based on the offset
355 * @data: Pointer to corresponding irq_data
356 * @offset: register offset using which event is controlled.
357 */
358static void ti_sci_inta_manage_event(struct irq_data *data, u32 offset)
359{
360 struct ti_sci_inta_event_desc *event_desc;
361 struct ti_sci_inta_vint_desc *vint_desc;
362 struct ti_sci_inta_irq_domain *inta;
363
364 event_desc = irq_data_get_irq_chip_data(data);
365 vint_desc = to_vint_desc(event_desc, event_desc->vint_bit);
366 inta = data->domain->host_data;
367
368 writeq_relaxed(BIT(event_desc->vint_bit),
369 inta->base + vint_desc->vint_id * 0x1000 + offset);
370}
371
372/**
373 * ti_sci_inta_mask_irq() - Mask an event
374 * @data: Pointer to corresponding irq_data
375 */
376static void ti_sci_inta_mask_irq(struct irq_data *data)
377{
378 ti_sci_inta_manage_event(data, VINT_ENABLE_CLR_OFFSET);
379}
380
381/**
382 * ti_sci_inta_unmask_irq() - Unmask an event
383 * @data: Pointer to corresponding irq_data
384 */
385static void ti_sci_inta_unmask_irq(struct irq_data *data)
386{
387 ti_sci_inta_manage_event(data, VINT_ENABLE_SET_OFFSET);
388}
389
390/**
391 * ti_sci_inta_ack_irq() - Ack an event
392 * @data: Pointer to corresponding irq_data
393 */
394static void ti_sci_inta_ack_irq(struct irq_data *data)
395{
396 /*
397 * Do not clear the event if hardware is capable of sending
398 * a down event.
399 */
400 if (irqd_get_trigger_type(data) != IRQF_TRIGGER_HIGH)
401 ti_sci_inta_manage_event(data, VINT_STATUS_OFFSET);
402}
403
404static int ti_sci_inta_set_affinity(struct irq_data *d,
405 const struct cpumask *mask_val, bool force)
406{
407 return -EINVAL;
408}
409
410/**
411 * ti_sci_inta_set_type() - Update the trigger type of the irq.
412 * @data: Pointer to corresponding irq_data
413 * @type: Trigger type as specified by user
414 *
415 * Note: This updates the handle_irq callback for level msi.
416 *
417 * Return 0 if all went well else appropriate error.
418 */
419static int ti_sci_inta_set_type(struct irq_data *data, unsigned int type)
420{
421 /*
422 * .alloc default sets handle_edge_irq. But if the user specifies
423 * that IRQ is level MSI, then update the handle to handle_level_irq
424 */
425 switch (type & IRQ_TYPE_SENSE_MASK) {
426 case IRQF_TRIGGER_HIGH:
427 irq_set_handler_locked(data, handle_level_irq);
428 return 0;
429 case IRQF_TRIGGER_RISING:
430 return 0;
431 default:
432 return -EINVAL;
433 }
434
435 return -EINVAL;
436}
437
438static struct irq_chip ti_sci_inta_irq_chip = {
439 .name = "INTA",
440 .irq_ack = ti_sci_inta_ack_irq,
441 .irq_mask = ti_sci_inta_mask_irq,
442 .irq_set_type = ti_sci_inta_set_type,
443 .irq_unmask = ti_sci_inta_unmask_irq,
444 .irq_set_affinity = ti_sci_inta_set_affinity,
445 .irq_request_resources = ti_sci_inta_request_resources,
446 .irq_release_resources = ti_sci_inta_release_resources,
447};
448
449/**
450 * ti_sci_inta_irq_domain_free() - Free an IRQ from the IRQ domain
451 * @domain: Domain to which the irqs belong
452 * @virq: base linux virtual IRQ to be freed.
453 * @nr_irqs: Number of continuous irqs to be freed
454 */
455static void ti_sci_inta_irq_domain_free(struct irq_domain *domain,
456 unsigned int virq, unsigned int nr_irqs)
457{
458 struct irq_data *data = irq_domain_get_irq_data(domain, virq);
459
460 irq_domain_reset_irq_data(data);
461}
462
463/**
464 * ti_sci_inta_irq_domain_alloc() - Allocate Interrupt aggregator IRQs
465 * @domain: Point to the interrupt aggregator IRQ domain
466 * @virq: Corresponding Linux virtual IRQ number
467 * @nr_irqs: Continuous irqs to be allocated
468 * @data: Pointer to firmware specifier
469 *
470 * No actual allocation happens here.
471 *
472 * Return 0 if all went well else appropriate error value.
473 */
474static int ti_sci_inta_irq_domain_alloc(struct irq_domain *domain,
475 unsigned int virq, unsigned int nr_irqs,
476 void *data)
477{
478 msi_alloc_info_t *arg = data;
479
480 irq_domain_set_info(domain, virq, arg->hwirq, &ti_sci_inta_irq_chip,
481 NULL, handle_edge_irq, NULL, NULL);
482
483 return 0;
484}
485
486static const struct irq_domain_ops ti_sci_inta_irq_domain_ops = {
487 .free = ti_sci_inta_irq_domain_free,
488 .alloc = ti_sci_inta_irq_domain_alloc,
489};
490
491static struct irq_chip ti_sci_inta_msi_irq_chip = {
492 .name = "MSI-INTA",
493 .flags = IRQCHIP_SUPPORTS_LEVEL_MSI,
494};
495
496static void ti_sci_inta_msi_set_desc(msi_alloc_info_t *arg,
497 struct msi_desc *desc)
498{
499 struct platform_device *pdev = to_platform_device(desc->dev);
500
501 arg->desc = desc;
502 arg->hwirq = TO_HWIRQ(pdev->id, desc->inta.dev_index);
503}
504
505static struct msi_domain_ops ti_sci_inta_msi_ops = {
506 .set_desc = ti_sci_inta_msi_set_desc,
507};
508
509static struct msi_domain_info ti_sci_inta_msi_domain_info = {
510 .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
511 MSI_FLAG_LEVEL_CAPABLE),
512 .ops = &ti_sci_inta_msi_ops,
513 .chip = &ti_sci_inta_msi_irq_chip,
514};
515
516static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
517{
518 struct irq_domain *parent_domain, *domain, *msi_domain;
519 struct device_node *parent_node, *node;
520 struct ti_sci_inta_irq_domain *inta;
521 struct device *dev = &pdev->dev;
522 struct resource *res;
523 int ret;
524
525 node = dev_of_node(dev);
526 parent_node = of_irq_find_parent(node);
527 if (!parent_node) {
528 dev_err(dev, "Failed to get IRQ parent node\n");
529 return -ENODEV;
530 }
531
532 parent_domain = irq_find_host(parent_node);
533 if (!parent_domain)
534 return -EPROBE_DEFER;
535
536 inta = devm_kzalloc(dev, sizeof(*inta), GFP_KERNEL);
537 if (!inta)
538 return -ENOMEM;
539
540 inta->pdev = pdev;
541 inta->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
542 if (IS_ERR(inta->sci)) {
543 ret = PTR_ERR(inta->sci);
544 if (ret != -EPROBE_DEFER)
545 dev_err(dev, "ti,sci read fail %d\n", ret);
546 inta->sci = NULL;
547 return ret;
548 }
549
550 ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &pdev->id);
551 if (ret) {
552 dev_err(dev, "missing 'ti,sci-dev-id' property\n");
553 return -EINVAL;
554 }
555
556 inta->vint = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
557 "ti,sci-rm-range-vint");
558 if (IS_ERR(inta->vint)) {
559 dev_err(dev, "VINT resource allocation failed\n");
560 return PTR_ERR(inta->vint);
561 }
562
563 inta->global_event = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
564 "ti,sci-rm-range-global-event");
565 if (IS_ERR(inta->global_event)) {
566 dev_err(dev, "Global event resource allocation failed\n");
567 return PTR_ERR(inta->global_event);
568 }
569
570 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
571 inta->base = devm_ioremap_resource(dev, res);
572 if (IS_ERR(inta->base))
573 return -ENODEV;
574
575 domain = irq_domain_add_linear(dev_of_node(dev),
576 ti_sci_get_num_resources(inta->vint),
577 &ti_sci_inta_irq_domain_ops, inta);
578 if (!domain) {
579 dev_err(dev, "Failed to allocate IRQ domain\n");
580 return -ENOMEM;
581 }
582
583 msi_domain = ti_sci_inta_msi_create_irq_domain(of_node_to_fwnode(node),
584 &ti_sci_inta_msi_domain_info,
585 domain);
586 if (!msi_domain) {
587 irq_domain_remove(domain);
588 dev_err(dev, "Failed to allocate msi domain\n");
589 return -ENOMEM;
590 }
591
592 INIT_LIST_HEAD(&inta->vint_list);
593 mutex_init(&inta->vint_mutex);
594
595 return 0;
596}
597
598static const struct of_device_id ti_sci_inta_irq_domain_of_match[] = {
599 { .compatible = "ti,sci-inta", },
600 { /* sentinel */ },
601};
602MODULE_DEVICE_TABLE(of, ti_sci_inta_irq_domain_of_match);
603
604static struct platform_driver ti_sci_inta_irq_domain_driver = {
605 .probe = ti_sci_inta_irq_domain_probe,
606 .driver = {
607 .name = "ti-sci-inta",
608 .of_match_table = ti_sci_inta_irq_domain_of_match,
609 },
610};
611module_platform_driver(ti_sci_inta_irq_domain_driver);
612
613MODULE_AUTHOR("Lokesh Vutla <lokeshvutla@ticom>");
614MODULE_DESCRIPTION("K3 Interrupt Aggregator driver over TI SCI protocol");
615MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c
new file mode 100644
index 000000000000..59d51a20bbd8
--- /dev/null
+++ b/drivers/irqchip/irq-ti-sci-intr.c
@@ -0,0 +1,275 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments' K3 Interrupt Router irqchip driver
4 *
5 * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Lokesh Vutla <lokeshvutla@ti.com>
7 */
8
9#include <linux/err.h>
10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/io.h>
13#include <linux/irqchip.h>
14#include <linux/irqdomain.h>
15#include <linux/of_platform.h>
16#include <linux/of_address.h>
17#include <linux/of_irq.h>
18#include <linux/soc/ti/ti_sci_protocol.h>
19
20#define TI_SCI_DEV_ID_MASK 0xffff
21#define TI_SCI_DEV_ID_SHIFT 16
22#define TI_SCI_IRQ_ID_MASK 0xffff
23#define TI_SCI_IRQ_ID_SHIFT 0
24#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
25 (TI_SCI_DEV_ID_MASK))
26#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
27#define TO_HWIRQ(dev, index) ((((dev) & TI_SCI_DEV_ID_MASK) << \
28 TI_SCI_DEV_ID_SHIFT) | \
29 ((index) & TI_SCI_IRQ_ID_MASK))
30
31/**
32 * struct ti_sci_intr_irq_domain - Structure representing a TISCI based
33 * Interrupt Router IRQ domain.
34 * @sci: Pointer to TISCI handle
35 * @dst_irq: TISCI resource pointer representing GIC irq controller.
36 * @dst_id: TISCI device ID of the GIC irq controller.
37 * @type: Specifies the trigger type supported by this Interrupt Router
38 */
39struct ti_sci_intr_irq_domain {
40 const struct ti_sci_handle *sci;
41 struct ti_sci_resource *dst_irq;
42 u32 dst_id;
43 u32 type;
44};
45
46static struct irq_chip ti_sci_intr_irq_chip = {
47 .name = "INTR",
48 .irq_eoi = irq_chip_eoi_parent,
49 .irq_mask = irq_chip_mask_parent,
50 .irq_unmask = irq_chip_unmask_parent,
51 .irq_set_type = irq_chip_set_type_parent,
52 .irq_retrigger = irq_chip_retrigger_hierarchy,
53 .irq_set_affinity = irq_chip_set_affinity_parent,
54};
55
56/**
57 * ti_sci_intr_irq_domain_translate() - Retrieve hwirq and type from
58 * IRQ firmware specific handler.
59 * @domain: Pointer to IRQ domain
60 * @fwspec: Pointer to IRQ specific firmware structure
61 * @hwirq: IRQ number identified by hardware
62 * @type: IRQ type
63 *
64 * Return 0 if all went ok else appropriate error.
65 */
66static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
67 struct irq_fwspec *fwspec,
68 unsigned long *hwirq,
69 unsigned int *type)
70{
71 struct ti_sci_intr_irq_domain *intr = domain->host_data;
72
73 if (fwspec->param_count != 2)
74 return -EINVAL;
75
76 *hwirq = TO_HWIRQ(fwspec->param[0], fwspec->param[1]);
77 *type = intr->type;
78
79 return 0;
80}
81
82/**
83 * ti_sci_intr_irq_domain_free() - Free the specified IRQs from the domain.
84 * @domain: Domain to which the irqs belong
85 * @virq: Linux virtual IRQ to be freed.
86 * @nr_irqs: Number of continuous irqs to be freed
87 */
88static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
89 unsigned int virq, unsigned int nr_irqs)
90{
91 struct ti_sci_intr_irq_domain *intr = domain->host_data;
92 struct irq_data *data, *parent_data;
93 u16 dev_id, irq_index;
94
95 parent_data = irq_domain_get_irq_data(domain->parent, virq);
96 data = irq_domain_get_irq_data(domain, virq);
97 irq_index = HWIRQ_TO_IRQID(data->hwirq);
98 dev_id = HWIRQ_TO_DEVID(data->hwirq);
99
100 intr->sci->ops.rm_irq_ops.free_irq(intr->sci, dev_id, irq_index,
101 intr->dst_id, parent_data->hwirq);
102 ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
103 irq_domain_free_irqs_parent(domain, virq, 1);
104 irq_domain_reset_irq_data(data);
105}
106
107/**
108 * ti_sci_intr_alloc_gic_irq() - Allocate GIC specific IRQ
109 * @domain: Pointer to the interrupt router IRQ domain
110 * @virq: Corresponding Linux virtual IRQ number
111 * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
112 *
113 * Returns 0 if all went well else appropriate error pointer.
114 */
115static int ti_sci_intr_alloc_gic_irq(struct irq_domain *domain,
116 unsigned int virq, u32 hwirq)
117{
118 struct ti_sci_intr_irq_domain *intr = domain->host_data;
119 struct irq_fwspec fwspec;
120 u16 dev_id, irq_index;
121 u16 dst_irq;
122 int err;
123
124 dev_id = HWIRQ_TO_DEVID(hwirq);
125 irq_index = HWIRQ_TO_IRQID(hwirq);
126
127 dst_irq = ti_sci_get_free_resource(intr->dst_irq);
128 if (dst_irq == TI_SCI_RESOURCE_NULL)
129 return -EINVAL;
130
131 fwspec.fwnode = domain->parent->fwnode;
132 fwspec.param_count = 3;
133 fwspec.param[0] = 0; /* SPI */
134 fwspec.param[1] = dst_irq - 32; /* SPI offset */
135 fwspec.param[2] = intr->type;
136
137 err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
138 if (err)
139 goto err_irqs;
140
141 err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci, dev_id, irq_index,
142 intr->dst_id, dst_irq);
143 if (err)
144 goto err_msg;
145
146 return 0;
147
148err_msg:
149 irq_domain_free_irqs_parent(domain, virq, 1);
150err_irqs:
151 ti_sci_release_resource(intr->dst_irq, dst_irq);
152 return err;
153}
154
155/**
156 * ti_sci_intr_irq_domain_alloc() - Allocate Interrupt router IRQs
157 * @domain: Point to the interrupt router IRQ domain
158 * @virq: Corresponding Linux virtual IRQ number
159 * @nr_irqs: Continuous irqs to be allocated
160 * @data: Pointer to firmware specifier
161 *
162 * Return 0 if all went well else appropriate error value.
163 */
164static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
165 unsigned int virq, unsigned int nr_irqs,
166 void *data)
167{
168 struct irq_fwspec *fwspec = data;
169 unsigned long hwirq;
170 unsigned int flags;
171 int err;
172
173 err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
174 if (err)
175 return err;
176
177 err = ti_sci_intr_alloc_gic_irq(domain, virq, hwirq);
178 if (err)
179 return err;
180
181 irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
182 &ti_sci_intr_irq_chip, NULL);
183
184 return 0;
185}
186
187static const struct irq_domain_ops ti_sci_intr_irq_domain_ops = {
188 .free = ti_sci_intr_irq_domain_free,
189 .alloc = ti_sci_intr_irq_domain_alloc,
190 .translate = ti_sci_intr_irq_domain_translate,
191};
192
193static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
194{
195 struct irq_domain *parent_domain, *domain;
196 struct ti_sci_intr_irq_domain *intr;
197 struct device_node *parent_node;
198 struct device *dev = &pdev->dev;
199 int ret;
200
201 parent_node = of_irq_find_parent(dev_of_node(dev));
202 if (!parent_node) {
203 dev_err(dev, "Failed to get IRQ parent node\n");
204 return -ENODEV;
205 }
206
207 parent_domain = irq_find_host(parent_node);
208 if (!parent_domain) {
209 dev_err(dev, "Failed to find IRQ parent domain\n");
210 return -ENODEV;
211 }
212
213 intr = devm_kzalloc(dev, sizeof(*intr), GFP_KERNEL);
214 if (!intr)
215 return -ENOMEM;
216
217 ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type",
218 &intr->type);
219 if (ret) {
220 dev_err(dev, "missing ti,intr-trigger-type property\n");
221 return -EINVAL;
222 }
223
224 intr->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
225 if (IS_ERR(intr->sci)) {
226 ret = PTR_ERR(intr->sci);
227 if (ret != -EPROBE_DEFER)
228 dev_err(dev, "ti,sci read fail %d\n", ret);
229 intr->sci = NULL;
230 return ret;
231 }
232
233 ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dst-id",
234 &intr->dst_id);
235 if (ret) {
236 dev_err(dev, "missing 'ti,sci-dst-id' property\n");
237 return -EINVAL;
238 }
239
240 intr->dst_irq = devm_ti_sci_get_of_resource(intr->sci, dev,
241 intr->dst_id,
242 "ti,sci-rm-range-girq");
243 if (IS_ERR(intr->dst_irq)) {
244 dev_err(dev, "Destination irq resource allocation failed\n");
245 return PTR_ERR(intr->dst_irq);
246 }
247
248 domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
249 &ti_sci_intr_irq_domain_ops, intr);
250 if (!domain) {
251 dev_err(dev, "Failed to allocate IRQ domain\n");
252 return -ENOMEM;
253 }
254
255 return 0;
256}
257
258static const struct of_device_id ti_sci_intr_irq_domain_of_match[] = {
259 { .compatible = "ti,sci-intr", },
260 { /* sentinel */ },
261};
262MODULE_DEVICE_TABLE(of, ti_sci_intr_irq_domain_of_match);
263
264static struct platform_driver ti_sci_intr_irq_domain_driver = {
265 .probe = ti_sci_intr_irq_domain_probe,
266 .driver = {
267 .name = "ti-sci-intr",
268 .of_match_table = ti_sci_intr_irq_domain_of_match,
269 },
270};
271module_platform_driver(ti_sci_intr_irq_domain_driver);
272
273MODULE_AUTHOR("Lokesh Vutla <lokeshvutla@ticom>");
274MODULE_DESCRIPTION("K3 Interrupt Router driver over TI SCI protocol");
275MODULE_LICENSE("GPL v2");