summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-19 10:58:45 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-19 10:58:45 -0700
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
config ARM_GIC
bool
- select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
@@ -33,7 +32,6 @@ config GIC_NON_BANKED
config ARM_GIC_V3
bool
- select IRQ_DOMAIN
select GENERIC_IRQ_MULTI_HANDLER
select IRQ_DOMAIN_HIERARCHY
select PARTITION_PERCPU
@@ -59,7 +57,6 @@ config ARM_GIC_V3_ITS_FSL_MC
config ARM_NVIC
bool
- select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
select GENERIC_IRQ_CHIP
@@ -358,7 +355,6 @@ config STM32_EXTI
config QCOM_IRQ_COMBINER
bool "QCOM IRQ combiner support"
depends on ARCH_QCOM && ACPI
- select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
help
Say yes here to add support for the IRQ combiner devices embedded
@@ -375,7 +371,6 @@ config IRQ_UNIPHIER_AIDET
config MESON_IRQ_GPIO
bool "Meson GPIO Interrupt Multiplexer"
depends on ARCH_MESON
- select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
help
Support Meson SoC Family GPIO Interrupt Multiplexer
@@ -391,7 +386,6 @@ config GOLDFISH_PIC
config QCOM_PDC
bool "QCOM PDC"
depends on ARCH_QCOM
- select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY
help
Power Domain Controller driver to manage and configure wakeup
@@ -431,6 +425,27 @@ config LS1X_IRQ
help
Support for the Loongson-1 platform Interrupt Controller.
+config TI_SCI_INTR_IRQCHIP
+ bool
+ depends on TI_SCI_PROTOCOL
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ This enables the irqchip driver support for K3 Interrupt router
+ over TI System Control Interface available on some new TI's SoCs.
+ If you wish to use interrupt router irq resources managed by the
+ TI System Controller, say Y here. Otherwise, say N.
+
+config TI_SCI_INTA_IRQCHIP
+ bool
+ depends on TI_SCI_PROTOCOL
+ select IRQ_DOMAIN_HIERARCHY
+ select TI_SCI_INTA_MSI_DOMAIN
+ help
+ This enables the irqchip driver support for K3 Interrupt aggregator
+ over TI System Control Interface available on some new TI's SoCs.
+ If you wish to use interrupt aggregator irq resources managed by the
+ TI System Controller, say Y here. Otherwise, say N.
+
endmenu
config 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
obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o
+obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o
+obj-$(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,
goto out_unmap;
}
+ pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
+ dn, IRQS_PER_WORD * intc->n_words);
+
return 0;
out_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,
}
}
+ pr_info("registered %s intc (%pOF, parent IRQ(s): %d)\n",
+ intc_name, dn, data->num_parent_irqs);
+
return 0;
out_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,
ct->chip.irq_set_wake = irq_gc_set_wake;
}
+ pr_info("registered L2 intc (%pOF, parent irq: %d)\n", np, parent_irq);
+
return 0;
out_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 @@
#include <linux/of_irq.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_device.h>
-#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
@@ -28,17 +27,27 @@ struct gic_clk_data {
const char *const *clocks;
};
+struct gic_chip_pm {
+ struct gic_chip_data *chip_data;
+ const struct gic_clk_data *clk_data;
+ struct clk_bulk_data *clks;
+};
+
static int gic_runtime_resume(struct device *dev)
{
- struct gic_chip_data *gic = dev_get_drvdata(dev);
+ struct gic_chip_pm *chip_pm = dev_get_drvdata(dev);
+ struct gic_chip_data *gic = chip_pm->chip_data;
+ const struct gic_clk_data *data = chip_pm->clk_data;
int ret;
- ret = pm_clk_resume(dev);
- if (ret)
+ ret = clk_bulk_prepare_enable(data->num_clocks, chip_pm->clks);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
return ret;
+ }
/*
- * On the very first resume, the pointer to the driver data
+ * On the very first resume, the pointer to chip_pm->chip_data
* will be NULL and this is intentional, because we do not
* want to restore the GIC on the very first resume. So if
* the pointer is not valid just return.
@@ -54,35 +63,14 @@ static int gic_runtime_resume(struct device *dev)
static int gic_runtime_suspend(struct device *dev)
{
- struct gic_chip_data *gic = dev_get_drvdata(dev);
+ struct gic_chip_pm *chip_pm = dev_get_drvdata(dev);
+ struct gic_chip_data *gic = chip_pm->chip_data;
+ const struct gic_clk_data *data = chip_pm->clk_data;
gic_dist_save(gic);
gic_cpu_save(gic);
- return pm_clk_suspend(dev);
-}
-
-static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data)
-{
- unsigned int i;
- int ret;
-
- if (!dev || !data)
- return -EINVAL;
-
- ret = pm_clk_create(dev);
- if (ret)
- return ret;
-
- for (i = 0; i < data->num_clocks; i++) {
- ret = of_pm_clk_add_clk(dev, data->clocks[i]);
- if (ret) {
- dev_err(dev, "failed to add clock %s\n",
- data->clocks[i]);
- pm_clk_destroy(dev);
- return ret;
- }
- }
+ clk_bulk_disable_unprepare(data->num_clocks, chip_pm->clks);
return 0;
}
@@ -91,8 +79,8 @@ static int gic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gic_clk_data *data;
- struct gic_chip_data *gic;
- int ret, irq;
+ struct gic_chip_pm *chip_pm;
+ int ret, irq, i;
data = of_device_get_match_data(&pdev->dev);
if (!data) {
@@ -100,28 +88,41 @@ static int gic_probe(struct platform_device *pdev)
return -ENODEV;
}
+ chip_pm = devm_kzalloc(dev, sizeof(*chip_pm), GFP_KERNEL);
+ if (!chip_pm)
+ return -ENOMEM;
+
irq = irq_of_parse_and_map(dev->of_node, 0);
if (!irq) {
dev_err(dev, "no parent interrupt found!\n");
return -EINVAL;
}
- ret = gic_get_clocks(dev, data);
+ chip_pm->clks = devm_kcalloc(dev, data->num_clocks,
+ sizeof(*chip_pm->clks), GFP_KERNEL);
+ if (!chip_pm->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < data->num_clocks; i++)
+ chip_pm->clks[i].id = data->clocks[i];
+
+ ret = devm_clk_bulk_get(dev, data->num_clocks, chip_pm->clks);
if (ret)
goto irq_dispose;
+ chip_pm->clk_data = data;
+ dev_set_drvdata(dev, chip_pm);
+
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto rpm_disable;
- ret = gic_of_init_child(dev, &gic, irq);
+ ret = gic_of_init_child(dev, &chip_pm->chip_data, irq);
if (ret)
goto rpm_put;
- platform_set_drvdata(pdev, gic);
-
pm_runtime_put(dev);
dev_info(dev, "GIC IRQ controller registered\n");
@@ -132,7 +133,6 @@ rpm_put:
pm_runtime_put_sync(dev);
rpm_disable:
pm_runtime_disable(dev);
- pm_clk_destroy(dev);
irq_dispose:
irq_dispose_mapping(irq);
@@ -142,6 +142,8 @@ irq_dispose:
static const struct dev_pm_ops gic_pm_ops = {
SET_RUNTIME_PM_OPS(gic_runtime_suspend,
gic_runtime_resume, NULL)
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
static 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)
if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
msg->data -= v2m->spi_offset;
- iommu_dma_map_msi_msg(data->irq, msg);
+ iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
}
static struct irq_chip gicv2m_irq_chip = {
@@ -167,6 +167,7 @@ static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq,
static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *args)
{
+ msi_alloc_info_t *info = args;
struct v2m_data *v2m = NULL, *tmp;
int hwirq, offset, i, err = 0;
@@ -186,6 +187,11 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
hwirq = v2m->spi_start + offset;
+ err = iommu_dma_prepare_msi(info->desc,
+ v2m->res.start + V2M_MSI_SETSPI_NS);
+ if (err)
+ return err;
+
for (i = 0; i < nr_irqs; i++) {
err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
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 @@
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/list.h>
-#include <linux/list_sort.h>
#include <linux/log2.h>
#include <linux/memblock.h>
#include <linux/mm.h>
@@ -1179,7 +1178,7 @@ static void its_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
msg->address_hi = upper_32_bits(addr);
msg->data = its_get_event_id(d);
- iommu_dma_map_msi_msg(d->irq, msg);
+ iommu_dma_compose_msi_msg(irq_data_get_msi_desc(d), msg);
}
static 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)
{
struct lpi_range *range;
- range = kzalloc(sizeof(*range), GFP_KERNEL);
+ range = kmalloc(sizeof(*range), GFP_KERNEL);
if (range) {
- INIT_LIST_HEAD(&range->entry);
range->base_id = base;
range->span = span;
}
@@ -1475,31 +1473,6 @@ static struct lpi_range *mk_lpi_range(u32 base, u32 span)
return range;
}
-static int lpi_range_cmp(void *priv, struct list_head *a, struct list_head *b)
-{
- struct lpi_range *ra, *rb;
-
- ra = container_of(a, struct lpi_range, entry);
- rb = container_of(b, struct lpi_range, entry);
-
- return ra->base_id - rb->base_id;
-}
-
-static void merge_lpi_ranges(void)
-{
- struct lpi_range *range, *tmp;
-
- list_for_each_entry_safe(range, tmp, &lpi_range_list, entry) {
- if (!list_is_last(&range->entry, &lpi_range_list) &&
- (tmp->base_id == (range->base_id + range->span))) {
- tmp->base_id = range->base_id;
- tmp->span += range->span;
- list_del(&range->entry);
- kfree(range);
- }
- }
-}
-
static int alloc_lpi_range(u32 nr_lpis, u32 *base)
{
struct lpi_range *range, *tmp;
@@ -1529,25 +1502,49 @@ static int alloc_lpi_range(u32 nr_lpis, u32 *base)
return err;
}
+static void merge_lpi_ranges(struct lpi_range *a, struct lpi_range *b)
+{
+ if (&a->entry == &lpi_range_list || &b->entry == &lpi_range_list)
+ return;
+ if (a->base_id + a->span != b->base_id)
+ return;
+ b->base_id = a->base_id;
+ b->span += a->span;
+ list_del(&a->entry);
+ kfree(a);
+}
+
static int free_lpi_range(u32 base, u32 nr_lpis)
{
- struct lpi_range *new;
- int err = 0;
+ struct lpi_range *new, *old;
+
+ new = mk_lpi_range(base, nr_lpis);
+ if (!new)
+ return -ENOMEM;
mutex_lock(&lpi_range_lock);
- new = mk_lpi_range(base, nr_lpis);
- if (!new) {
- err = -ENOMEM;
- goto out;
+ list_for_each_entry_reverse(old, &lpi_range_list, entry) {
+ if (old->base_id < base)
+ break;
}
+ /*
+ * old is the last element with ->base_id smaller than base,
+ * so new goes right after it. If there are no elements with
+ * ->base_id smaller than base, &old->entry ends up pointing
+ * at the head of the list, and inserting new it the start of
+ * the list is the right thing to do in that case as well.
+ */
+ list_add(&new->entry, &old->entry);
+ /*
+ * Now check if we can merge with the preceding and/or
+ * following ranges.
+ */
+ merge_lpi_ranges(old, new);
+ merge_lpi_ranges(new, list_next_entry(new, entry));
- list_add(&new->entry, &lpi_range_list);
- list_sort(NULL, &lpi_range_list, lpi_range_cmp);
- merge_lpi_ranges();
-out:
mutex_unlock(&lpi_range_lock);
- return err;
+ return 0;
}
static int __init its_lpi_init(u32 id_bits)
@@ -2487,7 +2484,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
int err = 0;
/*
- * We ignore "dev" entierely, and rely on the dev_id that has
+ * We ignore "dev" entirely, and rely on the dev_id that has
* been passed via the scratchpad. This limits this domain's
* usefulness to upper layers that definitely know that they
* are built on top of the ITS.
@@ -2566,6 +2563,7 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
{
msi_alloc_info_t *info = args;
struct its_device *its_dev = info->scratchpad[0].ptr;
+ struct its_node *its = its_dev->its;
irq_hw_number_t hwirq;
int err;
int i;
@@ -2574,6 +2572,10 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
if (err)
return err;
+ err = iommu_dma_prepare_msi(info->desc, its->get_msi_base(its_dev));
+ if (err)
+ return err;
+
for (i = 0; i < nr_irqs; i++) {
err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
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,
static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *args)
{
+ msi_alloc_info_t *info = args;
struct mbi_range *mbi = NULL;
int hwirq, offset, i, err = 0;
@@ -104,6 +105,11 @@ static int mbi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
hwirq = mbi->spi_start + offset;
+ err = iommu_dma_prepare_msi(info->desc,
+ mbi_phys_base + GICD_SETSPI_NSR);
+ if (err)
+ return err;
+
for (i = 0; i < nr_irqs; i++) {
err = mbi_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
if (err)
@@ -142,7 +148,7 @@ static void mbi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
msg[0].address_lo = lower_32_bits(mbi_phys_base + GICD_SETSPI_NSR);
msg[0].data = data->parent_data->hwirq;
- iommu_dma_map_msi_msg(data->irq, msg);
+ iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
}
#ifdef CONFIG_PCI_MSI
@@ -202,7 +208,7 @@ static void mbi_compose_mbi_msg(struct irq_data *data, struct msi_msg *msg)
msg[1].address_lo = lower_32_bits(mbi_phys_base + GICD_CLRSPI_NSR);
msg[1].data = data->parent_data->hwirq;
- iommu_dma_map_msi_msg(data->irq, &msg[1]);
+ iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), &msg[1]);
}
/* 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)
{
struct device_node *np = pdev->dev.of_node;
struct irqsteer_data *data;
- struct resource *res;
u32 irqs_num;
int i, ret;
@@ -152,8 +151,7 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->regs = devm_ioremap_resource(&pdev->dev, res);
+ data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs)) {
dev_err(&pdev->dev, "failed to initialize reg\n");
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)
msg->data |= cpumask_first(mask);
}
- iommu_dma_map_msi_msg(data->irq, msg);
+ iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
}
static 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,
unsigned int nr_irqs,
void *args)
{
+ msi_alloc_info_t *info = args;
struct ls_scfg_msi *msi_data = domain->host_data;
int pos, err = 0;
@@ -157,6 +158,10 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain,
if (err)
return err;
+ err = iommu_dma_prepare_msi(info->desc, msi_data->msiir_addr);
+ if (err)
+ return err;
+
irq_domain_set_info(domain, virq, pos,
&ls_scfg_msi_parent_chip, msi_data,
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)
int k;
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
- if (!p) {
- dev_err(dev, "failed to allocate driver data\n");
+ if (!p)
return -ENOMEM;
- }
/* deal with driver instance configuration */
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 @@
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -37,12 +39,6 @@ struct stm32_exti_bank {
#define UNDEF_REG ~0
-enum stm32_exti_hwspinlock {
- HWSPINLOCK_UNKNOWN,
- HWSPINLOCK_NONE,
- HWSPINLOCK_READY,
-};
-
struct stm32_desc_irq {
u32 exti;
u32 irq_parent;
@@ -69,8 +65,6 @@ struct stm32_exti_host_data {
void __iomem *base;
struct stm32_exti_chip_data *chips_data;
const struct stm32_exti_drv_data *drv_data;
- struct device_node *node;
- enum stm32_exti_hwspinlock hwlock_state;
struct hwspinlock *hwlock;
};
@@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d,
static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
{
- struct stm32_exti_host_data *host_data = chip_data->host_data;
- struct hwspinlock *hwlock;
- int id, ret = 0, timeout = 0;
-
- /* first time, check for hwspinlock availability */
- if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
- id = of_hwspin_lock_get_id(host_data->node, 0);
- if (id >= 0) {
- hwlock = hwspin_lock_request_specific(id);
- if (hwlock) {
- /* found valid hwspinlock */
- host_data->hwlock_state = HWSPINLOCK_READY;
- host_data->hwlock = hwlock;
- pr_debug("%s hwspinlock = %d\n", __func__, id);
- } else {
- host_data->hwlock_state = HWSPINLOCK_NONE;
- }
- } else if (id != -EPROBE_DEFER) {
- host_data->hwlock_state = HWSPINLOCK_NONE;
- } else {
- /* hwspinlock driver shall be ready at that stage */
- ret = -EPROBE_DEFER;
- }
- }
+ int ret, timeout = 0;
- if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) {
- /*
- * Use the x_raw API since we are under spin_lock protection.
- * Do not use the x_timeout API because we are under irq_disable
- * mode (see __setup_irq())
- */
- do {
- ret = hwspin_trylock_raw(host_data->hwlock);
- if (!ret)
- return 0;
-
- udelay(HWSPNLCK_RETRY_DELAY);
- timeout += HWSPNLCK_RETRY_DELAY;
- } while (timeout < HWSPNLCK_TIMEOUT);
-
- if (ret == -EBUSY)
- ret = -ETIMEDOUT;
- }
+ if (!chip_data->host_data->hwlock)
+ return 0;
+
+ /*
+ * Use the x_raw API since we are under spin_lock protection.
+ * Do not use the x_timeout API because we are under irq_disable
+ * mode (see __setup_irq())
+ */
+ do {
+ ret = hwspin_trylock_raw(chip_data->host_data->hwlock);
+ if (!ret)
+ return 0;
+
+ udelay(HWSPNLCK_RETRY_DELAY);
+ timeout += HWSPNLCK_RETRY_DELAY;
+ } while (timeout < HWSPNLCK_TIMEOUT);
+
+ if (ret == -EBUSY)
+ ret = -ETIMEDOUT;
if (ret)
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)
static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
{
- if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY))
+ if (chip_data->host_data->hwlock)
hwspin_unlock_raw(chip_data->host_data->hwlock);
}
@@ -586,8 +558,7 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
return -EINVAL;
}
-#ifdef CONFIG_PM
-static int stm32_exti_h_suspend(void)
+static int __maybe_unused stm32_exti_h_suspend(void)
{
struct stm32_exti_chip_data *chip_data;
int i;
@@ -602,7 +573,7 @@ static int stm32_exti_h_suspend(void)
return 0;
}
-static void stm32_exti_h_resume(void)
+static void __maybe_unused stm32_exti_h_resume(void)
{
struct stm32_exti_chip_data *chip_data;
int i;
@@ -616,17 +587,22 @@ static void stm32_exti_h_resume(void)
}
static struct syscore_ops stm32_exti_h_syscore_ops = {
+#ifdef CONFIG_PM_SLEEP
.suspend = stm32_exti_h_suspend,
.resume = stm32_exti_h_resume,
+#endif
};
-static void stm32_exti_h_syscore_init(void)
+static void stm32_exti_h_syscore_init(struct stm32_exti_host_data *host_data)
{
+ stm32_host_data = host_data;
register_syscore_ops(&stm32_exti_h_syscore_ops);
}
-#else
-static inline void stm32_exti_h_syscore_init(void) {}
-#endif
+
+static void stm32_exti_h_syscore_deinit(void)
+{
+ unregister_syscore_ops(&stm32_exti_h_syscore_ops);
+}
static struct irq_chip stm32_exti_h_chip = {
.name = "stm32-exti-h",
@@ -683,8 +659,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
return NULL;
host_data->drv_data = dd;
- host_data->node = node;
- host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
host_data->chips_data = kcalloc(dd->bank_nr,
sizeof(struct stm32_exti_chip_data),
GFP_KERNEL);
@@ -711,7 +685,8 @@ free_host_data:
static struct
stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
- u32 bank_idx)
+ u32 bank_idx,
+ struct device_node *node)
{
const struct stm32_exti_bank *stm32_bank;
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,
writel_relaxed(0, base + stm32_bank->imr_ofst);
writel_relaxed(0, base + stm32_bank->emr_ofst);
- pr_info("%pOF: bank%d\n", h_data->node, bank_idx);
+ pr_info("%pOF: bank%d\n", node, bank_idx);
return chip_data;
}
@@ -771,7 +746,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
struct stm32_exti_chip_data *chip_data;
stm32_bank = drv_data->exti_banks[i];
- chip_data = stm32_exti_chip_init(host_data, i);
+ chip_data = stm32_exti_chip_init(host_data, i, node);
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
@@ -815,50 +790,130 @@ static const struct irq_domain_ops stm32_exti_h_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
-static int
-__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data,
- struct device_node *node,
- struct device_node *parent)
+static void stm32_exti_remove_irq(void *data)
+{
+ struct irq_domain *domain = data;
+
+ irq_domain_remove(domain);
+}
+
+static int stm32_exti_remove(struct platform_device *pdev)
+{
+ stm32_exti_h_syscore_deinit();
+ return 0;
+}
+
+static int stm32_exti_probe(struct platform_device *pdev)
{
+ int ret, i;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct irq_domain *parent_domain, *domain;
struct stm32_exti_host_data *host_data;
- int ret, i;
+ const struct stm32_exti_drv_data *drv_data;
+ struct resource *res;
- parent_domain = irq_find_host(parent);
- if (!parent_domain) {
- pr_err("interrupt-parent not found\n");
- return -EINVAL;
+ host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
+ if (!host_data)
+ return -ENOMEM;
+
+ /* check for optional hwspinlock which may be not available yet */
+ ret = of_hwspin_lock_get_id(np, 0);
+ if (ret == -EPROBE_DEFER)
+ /* hwspinlock framework not yet ready */
+ return ret;
+
+ if (ret >= 0) {
+ host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
+ if (!host_data->hwlock) {
+ dev_err(dev, "Failed to request hwspinlock\n");
+ return -EINVAL;
+ }
+ } else if (ret != -ENOENT) {
+ /* note: ENOENT is a valid case (means 'no hwspinlock') */
+ dev_err(dev, "Failed to get hwspinlock\n");
+ return ret;
}
- host_data = stm32_exti_host_init(drv_data, node);
- if (!host_data)
+ /* initialize host_data */
+ drv_data = of_device_get_match_data(dev);
+ if (!drv_data) {
+ dev_err(dev, "no of match data\n");
+ return -ENODEV;
+ }
+ host_data->drv_data = drv_data;
+
+ host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr,
+ sizeof(*host_data->chips_data),
+ GFP_KERNEL);
+ if (!host_data->chips_data)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ host_data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(host_data->base)) {
+ dev_err(dev, "Unable to map registers\n");
+ return PTR_ERR(host_data->base);
+ }
+
for (i = 0; i < drv_data->bank_nr; i++)
- stm32_exti_chip_init(host_data, i);
+ stm32_exti_chip_init(host_data, i, np);
+
+ parent_domain = irq_find_host(of_irq_find_parent(np));
+ if (!parent_domain) {
+ dev_err(dev, "GIC interrupt-parent not found\n");
+ return -EINVAL;
+ }
domain = irq_domain_add_hierarchy(parent_domain, 0,
drv_data->bank_nr * IRQS_PER_BANK,
- node, &stm32_exti_h_domain_ops,
+ np, &stm32_exti_h_domain_ops,
host_data);
if (!domain) {
- pr_err("%pOFn: Could not register exti domain.\n", node);
- ret = -ENOMEM;
- goto out_unmap;
+ dev_err(dev, "Could not register exti domain\n");
+ return -ENOMEM;
}
- stm32_exti_h_syscore_init();
+ ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, domain);
+ if (ret)
+ return ret;
+
+ stm32_exti_h_syscore_init(host_data);
return 0;
+}
-out_unmap:
- iounmap(host_data->base);
- kfree(host_data->chips_data);
- kfree(host_data);
- return ret;
+/* platform driver only for MP1 */
+static const struct of_device_id stm32_exti_ids[] = {
+ { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_exti_ids);
+
+static struct platform_driver stm32_exti_driver = {
+ .probe = stm32_exti_probe,
+ .remove = stm32_exti_remove,
+ .driver = {
+ .name = "stm32_exti",
+ .of_match_table = stm32_exti_ids,
+ },
+};
+
+static int __init stm32_exti_arch_init(void)
+{
+ return platform_driver_register(&stm32_exti_driver);
}
+static void __exit stm32_exti_arch_exit(void)
+{
+ return platform_driver_unregister(&stm32_exti_driver);
+}
+
+arch_initcall(stm32_exti_arch_init);
+module_exit(stm32_exti_arch_exit);
+