aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/Kconfig7
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-alpine-msi.c3
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c2
-rw-r--r--drivers/irqchip/irq-bcm2836.c2
-rw-r--r--drivers/irqchip/irq-eznps.c165
-rw-r--r--drivers/irqchip/irq-gic-v3-its-pci-msi.c11
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c33
-rw-r--r--drivers/irqchip/irq-gic-v3.c6
-rw-r--r--drivers/irqchip/irq-gic-v4.c19
-rw-r--r--drivers/irqchip/irq-gic.c10
-rw-r--r--drivers/irqchip/irq-hip04.c6
-rw-r--r--drivers/irqchip/irq-loongson-htpic.c7
-rw-r--r--drivers/irqchip/irq-ls-extirq.c16
-rw-r--r--drivers/irqchip/irq-mscc-ocelot.c146
-rw-r--r--drivers/irqchip/irq-sni-exiu.c2
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c2
-rw-r--r--drivers/irqchip/irq-ti-sci-intr.c14
-rw-r--r--drivers/irqchip/qcom-pdc.c21
19 files changed, 209 insertions, 264 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 2aa79c32ee22..94920a51c628 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -387,13 +387,6 @@ config LS_SCFG_MSI
config PARTITION_PERCPU
bool
-config EZNPS_GIC
- bool "NPS400 Global Interrupt Manager (GIM)"
- depends on ARC || (COMPILE_TEST && !64BIT)
- select IRQ_DOMAIN
- help
- Support the EZchip NPS400 global interrupt controller
-
config STM32_EXTI
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 94c2885882ee..0ac93bfaec61 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -86,7 +86,6 @@ obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
-obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c
index 23a3b877f7f1..ede02dc2bcd0 100644
--- a/drivers/irqchip/irq-alpine-msi.c
+++ b/drivers/irqchip/irq-alpine-msi.c
@@ -165,8 +165,7 @@ static int alpine_msix_middle_domain_alloc(struct irq_domain *domain,
return 0;
err_sgi:
- while (--i >= 0)
- irq_domain_free_irqs_parent(domain, virq, i);
+ irq_domain_free_irqs_parent(domain, virq, i - 1);
alpine_msix_free_sgi(priv, sgi, nr_irqs);
return err;
}
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index d7eb2e93db8f..32938dfc0e46 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -382,7 +382,7 @@ static int armada_370_xp_ipi_alloc(struct irq_domain *d,
irq_set_percpu_devid(virq + i);
irq_domain_set_info(d, virq + i, i, &ipi_irqchip,
d->host_data,
- handle_percpu_devid_fasteoi_ipi,
+ handle_percpu_devid_irq,
NULL, NULL);
}
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
index cbc7c740e4dc..5f5eb8877c41 100644
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -209,7 +209,7 @@ static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d,
irq_set_percpu_devid(virq + i);
irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi,
d->host_data,
- handle_percpu_devid_fasteoi_ipi,
+ handle_percpu_devid_irq,
NULL, NULL);
}
diff --git a/drivers/irqchip/irq-eznps.c b/drivers/irqchip/irq-eznps.c
deleted file mode 100644
index 2a7a38830a8d..000000000000
--- a/drivers/irqchip/irq-eznps.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/irqchip.h>
-#include <soc/nps/common.h>
-
-#define NPS_NR_CPU_IRQS 8 /* number of interrupt lines of NPS400 CPU */
-#define NPS_TIMER0_IRQ 3
-
-/*
- * NPS400 core includes an Interrupt Controller (IC) support.
- * All cores can deactivate level irqs at first level control
- * at cores mesh layer called MTM.
- * For devices out side chip e.g. uart, network there is another
- * level called Global Interrupt Manager (GIM).
- * This second level can control level and edge interrupt.
- *
- * NOTE: AUX_IENABLE and CTOP_AUX_IACK are auxiliary registers
- * with private HW copy per CPU.
- */
-
-static void nps400_irq_mask(struct irq_data *irqd)
-{
- unsigned int ienb;
- unsigned int irq = irqd_to_hwirq(irqd);
-
- ienb = read_aux_reg(AUX_IENABLE);
- ienb &= ~(1 << irq);
- write_aux_reg(AUX_IENABLE, ienb);
-}
-
-static void nps400_irq_unmask(struct irq_data *irqd)
-{
- unsigned int ienb;
- unsigned int irq = irqd_to_hwirq(irqd);
-
- ienb = read_aux_reg(AUX_IENABLE);
- ienb |= (1 << irq);
- write_aux_reg(AUX_IENABLE, ienb);
-}
-
-static void nps400_irq_eoi_global(struct irq_data *irqd)
-{
- unsigned int __maybe_unused irq = irqd_to_hwirq(irqd);
-
- write_aux_reg(CTOP_AUX_IACK, 1 << irq);
-
- /* Don't ack GIC before all device access attempts are done */
- mb();
-
- nps_ack_gic();
-}
-
-static void nps400_irq_ack(struct irq_data *irqd)
-{
- unsigned int __maybe_unused irq = irqd_to_hwirq(irqd);
-
- write_aux_reg(CTOP_AUX_IACK, 1 << irq);
-}
-
-static struct irq_chip nps400_irq_chip_fasteoi = {
- .name = "NPS400 IC Global",
- .irq_mask = nps400_irq_mask,
- .irq_unmask = nps400_irq_unmask,
- .irq_eoi = nps400_irq_eoi_global,
-};
-
-static struct irq_chip nps400_irq_chip_percpu = {
- .name = "NPS400 IC",
- .irq_mask = nps400_irq_mask,
- .irq_unmask = nps400_irq_unmask,
- .irq_ack = nps400_irq_ack,
-};
-
-static int nps400_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hw)
-{
- switch (hw) {
- case NPS_TIMER0_IRQ:
-#ifdef CONFIG_SMP
- case NPS_IPI_IRQ:
-#endif
- irq_set_percpu_devid(virq);
- irq_set_chip_and_handler(virq, &nps400_irq_chip_percpu,
- handle_percpu_devid_irq);
- break;
- default:
- irq_set_chip_and_handler(virq, &nps400_irq_chip_fasteoi,
- handle_fasteoi_irq);
- break;
- }
-
- return 0;
-}
-
-static const struct irq_domain_ops nps400_irq_ops = {
- .xlate = irq_domain_xlate_onecell,
- .map = nps400_irq_map,
-};
-
-static int __init nps400_of_init(struct device_node *node,
- struct device_node *parent)
-{
- struct irq_domain *nps400_root_domain;
-
- if (parent) {
- pr_err("DeviceTree incore ic not a root irq controller\n");
- return -EINVAL;
- }
-
- nps400_root_domain = irq_domain_add_linear(node, NPS_NR_CPU_IRQS,
- &nps400_irq_ops, NULL);
-
- if (!nps400_root_domain) {
- pr_err("nps400 root irq domain not avail\n");
- return -ENOMEM;
- }
-
- /*
- * Needed for primary domain lookup to succeed
- * This is a primary irqchip, and can never have a parent
- */
- irq_set_default_host(nps400_root_domain);
-
-#ifdef CONFIG_SMP
- irq_create_mapping(nps400_root_domain, NPS_IPI_IRQ);
-#endif
-
- return 0;
-}
-IRQCHIP_DECLARE(ezchip_nps400_ic, "ezchip,nps400-ic", nps400_of_init);
diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
index 87711e0f8014..ad2810c017ed 100644
--- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c
+++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c
@@ -67,11 +67,16 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
/*
* If pdev is downstream of any aliasing bridges, take an upper
* bound of how many other vectors could map to the same DevID.
+ * Also tell the ITS that the signalling will come from a proxy
+ * device, and that special allocation rules apply.
*/
pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
- if (alias_dev != pdev && alias_dev->subordinate)
- pci_walk_bus(alias_dev->subordinate, its_pci_msi_vec_count,
- &alias_count);
+ if (alias_dev != pdev) {
+ if (alias_dev->subordinate)
+ pci_walk_bus(alias_dev->subordinate,
+ its_pci_msi_vec_count, &alias_count);
+ info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
+ }
/* ITS specific DeviceID, as the core ITS ignores dev. */
info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev);
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 0fec31931e11..ed46e6057e33 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -42,7 +42,6 @@
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0)
#define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1)
#define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2)
-#define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
@@ -3488,6 +3487,9 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
goto out;
}
+ if (info->flags & MSI_ALLOC_FLAGS_PROXY_DEVICE)
+ its_dev->shared = true;
+
pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec));
out:
mutex_unlock(&its->dev_alloc_lock);
@@ -3809,7 +3811,7 @@ static void its_wait_vpt_parse_complete(void)
WARN_ON_ONCE(readq_relaxed_poll_timeout_atomic(vlpi_base + GICR_VPENDBASER,
val,
!(val & GICR_VPENDBASER_Dirty),
- 10, 500));
+ 1, 500));
}
static void its_vpe_schedule(struct its_vpe *vpe)
@@ -3842,8 +3844,6 @@ static void its_vpe_schedule(struct its_vpe *vpe)
val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0;
val |= GICR_VPENDBASER_Valid;
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
-
- its_wait_vpt_parse_complete();
}
static void its_vpe_deschedule(struct its_vpe *vpe)
@@ -3891,6 +3891,10 @@ static int its_vpe_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
its_vpe_deschedule(vpe);
return 0;
+ case COMMIT_VPE:
+ its_wait_vpt_parse_complete();
+ return 0;
+
case INVALL_VPE:
its_vpe_invall(vpe);
return 0;
@@ -4052,8 +4056,6 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe,
val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id);
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
-
- its_wait_vpt_parse_complete();
}
static void its_vpe_4_1_deschedule(struct its_vpe *vpe,
@@ -4128,6 +4130,10 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
its_vpe_4_1_deschedule(vpe, info);
return 0;
+ case COMMIT_VPE:
+ its_wait_vpt_parse_complete();
+ return 0;
+
case INVALL_VPE:
its_vpe_4_1_invall(vpe);
return 0;
@@ -4741,9 +4747,6 @@ static int its_save_disable(void)
list_for_each_entry(its, &its_nodes, entry) {
void __iomem *base;
- if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
- continue;
-
base = its->base;
its->ctlr_save = readl_relaxed(base + GITS_CTLR);
err = its_force_quiescent(base);
@@ -4762,9 +4765,6 @@ err:
list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
void __iomem *base;
- if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
- continue;
-
base = its->base;
writel_relaxed(its->ctlr_save, base + GITS_CTLR);
}
@@ -4784,9 +4784,6 @@ static void its_restore_enable(void)
void __iomem *base;
int i;
- if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
- continue;
-
base = its->base;
/*
@@ -4794,7 +4791,10 @@ static void its_restore_enable(void)
* don't restore it since writing to CBASER or BASER<n>
* registers is undefined according to the GIC v3 ITS
* Specification.
+ *
+ * Firmware resuming with the ITS enabled is terminally broken.
*/
+ WARN_ON(readl_relaxed(base + GITS_CTLR) & GITS_CTLR_ENABLE);
ret = its_force_quiescent(base);
if (ret) {
pr_err("ITS@%pa: failed to quiesce on resume: %d\n",
@@ -5074,9 +5074,6 @@ static int __init its_probe_one(struct resource *res,
ctlr |= GITS_CTLR_ImDe;
writel_relaxed(ctlr, its->base + GITS_CTLR);
- if (GITS_TYPER_HCC(typer))
- its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
-
err = its_init_domain(handle, its);
if (err)
goto out_free_tables;
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 16fecc0febe8..3fc65375cbe0 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1302,12 +1302,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
switch (__get_intid_range(hw)) {
case SGI_RANGE:
- irq_set_percpu_devid(irq);
- irq_domain_set_info(d, irq, hw, chip, d->host_data,
- handle_percpu_devid_fasteoi_ipi,
- NULL, NULL);
- break;
-
case PPI_RANGE:
case EPPI_RANGE:
irq_set_percpu_devid(irq);
diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
index 0c18714ae13e..5d1dc9915272 100644
--- a/drivers/irqchip/irq-gic-v4.c
+++ b/drivers/irqchip/irq-gic-v4.c
@@ -232,6 +232,8 @@ int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
if (!ret)
vpe->resident = false;
+ vpe->ready = false;
+
return ret;
}
@@ -258,6 +260,23 @@ int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en)
return ret;
}
+int its_commit_vpe(struct its_vpe *vpe)
+{
+ struct its_cmd_info info = {
+ .cmd_type = COMMIT_VPE,
+ };
+ int ret;
+
+ WARN_ON(preemptible());
+
+ ret = its_send_vpe_cmd(vpe, &info);
+ if (!ret)
+ vpe->ready = true;
+
+ return ret;
+}
+
+
int its_invall_vpe(struct its_vpe *vpe)
{
struct its_cmd_info info = {
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 6053245a4754..b1d9c22caf2e 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -973,7 +973,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
/*
* gic_get_sgir_physaddr - get the physical address for the SGI register
*
- * REturn the physical address of the SGI register to be used
+ * Return the physical address of the SGI register to be used
* by some early assembly code when the kernel is not yet available.
*/
static unsigned long gic_dist_physaddr;
@@ -1005,13 +1005,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq));
switch (hw) {
- case 0 ... 15:
- irq_set_percpu_devid(irq);
- irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
- handle_percpu_devid_fasteoi_ipi,
- NULL, NULL);
- break;
- case 16 ... 31:
+ case 0 ... 31:
irq_set_percpu_devid(irq);
irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL);
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 9b73dcfaf48d..a6ed877d9dd3 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -296,11 +296,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
- if (hw < 16) {
- irq_set_percpu_devid(irq);
- irq_set_chip_and_handler(irq, &hip04_irq_chip,
- handle_percpu_devid_fasteoi_ipi);
- } else if (hw < 32) {
+ if (hw < 32) {
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &hip04_irq_chip,
handle_percpu_devid_irq);
diff --git a/drivers/irqchip/irq-loongson-htpic.c b/drivers/irqchip/irq-loongson-htpic.c
index 63f72803c8c4..1b801c4fb026 100644
--- a/drivers/irqchip/irq-loongson-htpic.c
+++ b/drivers/irqchip/irq-loongson-htpic.c
@@ -59,11 +59,10 @@ static void htpic_reg_init(void)
int i;
for (i = 0; i < HTINT_NUM_VECTORS; i++) {
- uint32_t val;
-
/* Disable all HT Vectors */
writel(0x0, htpic->base + HTINT_EN_OFF + i * 0x4);
- val = readl(htpic->base + i * 0x4);
+ /* Read back to force write */
+ (void) readl(htpic->base + i * 0x4);
/* Ack all possible pending IRQs */
writel(GENMASK(31, 0), htpic->base + i * 0x4);
}
@@ -81,7 +80,7 @@ struct syscore_ops htpic_syscore_ops = {
.resume = htpic_resume,
};
-int __init htpic_of_init(struct device_node *node, struct device_node *parent)
+static int __init htpic_of_init(struct device_node *node, struct device_node *parent)
{
unsigned int parent_irq[4];
int i, err;
diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
index 4d1179fed77c..f94f974a8764 100644
--- a/drivers/irqchip/irq-ls-extirq.c
+++ b/drivers/irqchip/irq-ls-extirq.c
@@ -18,7 +18,7 @@
struct ls_extirq_data {
struct regmap *syscon;
u32 intpcr;
- bool bit_reverse;
+ bool is_ls1021a_or_ls1043a;
u32 nirq;
struct irq_fwspec map[MAXIRQ];
};
@@ -30,7 +30,7 @@ ls_extirq_set_type(struct irq_data *data, unsigned int type)
irq_hw_number_t hwirq = data->hwirq;
u32 value, mask;
- if (priv->bit_reverse)
+ if (priv->is_ls1021a_or_ls1043a)
mask = 1U << (31 - hwirq);
else
mask = 1U << hwirq;
@@ -174,14 +174,8 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
if (ret)
goto out;
- if (of_device_is_compatible(node, "fsl,ls1021a-extirq")) {
- u32 revcr;
-
- ret = regmap_read(priv->syscon, LS1021A_SCFGREVCR, &revcr);
- if (ret)
- goto out;
- priv->bit_reverse = (revcr != 0);
- }
+ priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") ||
+ of_device_is_compatible(node, "fsl,ls1043a-extirq");
domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node,
&extirq_domain_ops, priv);
@@ -195,3 +189,5 @@ out:
}
IRQCHIP_DECLARE(ls1021a_extirq, "fsl,ls1021a-extirq", ls_extirq_of_init);
+IRQCHIP_DECLARE(ls1043a_extirq, "fsl,ls1043a-extirq", ls_extirq_of_init);
+IRQCHIP_DECLARE(ls1088a_extirq, "fsl,ls1088a-extirq", ls_extirq_of_init);
diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c
index 88143c0b700c..8235d98650c1 100644
--- a/drivers/irqchip/irq-mscc-ocelot.c
+++ b/drivers/irqchip/irq-mscc-ocelot.c
@@ -12,30 +12,85 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/interrupt.h>
-#define ICPU_CFG_INTR_INTR_STICKY 0x10
-#define ICPU_CFG_INTR_INTR_ENA 0x18
-#define ICPU_CFG_INTR_INTR_ENA_CLR 0x1c
-#define ICPU_CFG_INTR_INTR_ENA_SET 0x20
-#define ICPU_CFG_INTR_DST_INTR_IDENT(x) (0x38 + 0x4 * (x))
-#define ICPU_CFG_INTR_INTR_TRIGGER(x) (0x5c + 0x4 * (x))
-
-#define OCELOT_NR_IRQ 24
+#define ICPU_CFG_INTR_DST_INTR_IDENT(_p, x) ((_p)->reg_off_ident + 0x4 * (x))
+#define ICPU_CFG_INTR_INTR_TRIGGER(_p, x) ((_p)->reg_off_trigger + 0x4 * (x))
+
+#define FLAGS_HAS_TRIGGER BIT(0)
+#define FLAGS_NEED_INIT_ENABLE BIT(1)
+
+struct chip_props {
+ u8 flags;
+ u8 reg_off_sticky;
+ u8 reg_off_ena;
+ u8 reg_off_ena_clr;
+ u8 reg_off_ena_set;
+ u8 reg_off_ident;
+ u8 reg_off_trigger;
+ u8 reg_off_ena_irq0;
+ u8 n_irq;
+};
+
+static struct chip_props ocelot_props = {
+ .flags = FLAGS_HAS_TRIGGER,
+ .reg_off_sticky = 0x10,
+ .reg_off_ena = 0x18,
+ .reg_off_ena_clr = 0x1c,
+ .reg_off_ena_set = 0x20,
+ .reg_off_ident = 0x38,
+ .reg_off_trigger = 0x5c,
+ .n_irq = 24,
+};
+
+static struct chip_props serval_props = {
+ .flags = FLAGS_HAS_TRIGGER,
+ .reg_off_sticky = 0xc,
+ .reg_off_ena = 0x14,
+ .reg_off_ena_clr = 0x18,
+ .reg_off_ena_set = 0x1c,
+ .reg_off_ident = 0x20,
+ .reg_off_trigger = 0x4,
+ .n_irq = 24,
+};
+
+static struct chip_props luton_props = {
+ .flags = FLAGS_NEED_INIT_ENABLE,
+ .reg_off_sticky = 0,
+ .reg_off_ena = 0x4,
+ .reg_off_ena_clr = 0x8,
+ .reg_off_ena_set = 0xc,
+ .reg_off_ident = 0x18,
+ .reg_off_ena_irq0 = 0x14,
+ .n_irq = 28,
+};
+
+static struct chip_props jaguar2_props = {
+ .flags = FLAGS_HAS_TRIGGER,
+ .reg_off_sticky = 0x10,
+ .reg_off_ena = 0x18,
+ .reg_off_ena_clr = 0x1c,
+ .reg_off_ena_set = 0x20,
+ .reg_off_ident = 0x38,
+ .reg_off_trigger = 0x5c,
+ .n_irq = 29,
+};
static void ocelot_irq_unmask(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ struct irq_domain *d = data->domain;
+ struct chip_props *p = d->host_data;
struct irq_chip_type *ct = irq_data_get_chip_type(data);
unsigned int mask = data->mask;
u32 val;
irq_gc_lock(gc);
- val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(0)) |
- irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(1));
+ val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 0)) |
+ irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 1));
if (!(val & mask))
- irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_STICKY);
+ irq_reg_writel(gc, mask, p->reg_off_sticky);
*ct->mask_cache &= ~mask;
- irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_ENA_SET);
+ irq_reg_writel(gc, mask, p->reg_off_ena_set);
irq_gc_unlock(gc);
}
@@ -43,8 +98,9 @@ static void ocelot_irq_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct irq_domain *d = irq_desc_get_handler_data(desc);
+ struct chip_props *p = d->host_data;
struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
- u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(0));
+ u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(p, 0));
chained_irq_enter(chip, desc);
@@ -58,8 +114,9 @@ static void ocelot_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static int __init ocelot_irq_init(struct device_node *node,
- struct device_node *parent)
+static int __init vcoreiii_irq_init(struct device_node *node,
+ struct device_node *parent,
+ struct chip_props *p)
{
struct irq_domain *domain;
struct irq_chip_generic *gc;
@@ -69,14 +126,14 @@ static int __init ocelot_irq_init(struct device_node *node,
if (!parent_irq)
return -EINVAL;
- domain = irq_domain_add_linear(node, OCELOT_NR_IRQ,
+ domain = irq_domain_add_linear(node, p->n_irq,
&irq_generic_chip_ops, NULL);
if (!domain) {
pr_err("%pOFn: unable to add irq domain\n", node);
return -ENOMEM;
}
- ret = irq_alloc_domain_generic_chips(domain, OCELOT_NR_IRQ, 1,
+ ret = irq_alloc_domain_generic_chips(domain, p->n_irq, 1,
"icpu", handle_level_irq,
0, 0, 0);
if (ret) {
@@ -92,16 +149,28 @@ static int __init ocelot_irq_init(struct device_node *node,
goto err_gc_free;
}
- gc->chip_types[0].regs.ack = ICPU_CFG_INTR_INTR_STICKY;
- gc->chip_types[0].regs.mask = ICPU_CFG_INTR_INTR_ENA_CLR;
gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
- gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
- gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask;
+ gc->chip_types[0].regs.ack = p->reg_off_sticky;
+ if (p->flags & FLAGS_HAS_TRIGGER) {
+ gc->chip_types[0].regs.mask = p->reg_off_ena_clr;
+ gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
+ } else {
+ gc->chip_types[0].regs.enable = p->reg_off_ena_set;
+ gc->chip_types[0].regs.disable = p->reg_off_ena_clr;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
+ }
/* Mask and ack all interrupts */
- irq_reg_writel(gc, 0, ICPU_CFG_INTR_INTR_ENA);
- irq_reg_writel(gc, 0xffffffff, ICPU_CFG_INTR_INTR_STICKY);
+ irq_reg_writel(gc, 0, p->reg_off_ena);
+ irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky);
+
+ /* Overall init */
+ if (p->flags & FLAGS_NEED_INIT_ENABLE)
+ irq_reg_writel(gc, BIT(0), p->reg_off_ena_irq0);
+ domain->host_data = p;
irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler,
domain);
@@ -115,4 +184,35 @@ err_domain_remove:
return ret;
}
+
+static int __init ocelot_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return vcoreiii_irq_init(node, parent, &ocelot_props);
+}
+
IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init);
+
+static int __init serval_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return vcoreiii_irq_init(node, parent, &serval_props);
+}
+
+IRQCHIP_DECLARE(serval_icpu, "mscc,serval-icpu-intr", serval_irq_init);
+
+static int __init luton_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return vcoreiii_irq_init(node, parent, &luton_props);
+}
+
+IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init);
+
+static int __init jaguar2_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return vcoreiii_irq_init(node, parent, &jaguar2_props);
+}
+
+IRQCHIP_DECLARE(jaguar2_icpu, "mscc,jaguar2-icpu-intr", jaguar2_irq_init);
diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c
index 1d027623c776..abd011fcecf4 100644
--- a/drivers/irqchip/irq-sni-exiu.c
+++ b/drivers/irqchip/irq-sni-exiu.c
@@ -136,7 +136,7 @@ static int exiu_domain_translate(struct irq_domain *domain,
if (fwspec->param_count != 2)
return -EINVAL;
*hwirq = fwspec->param[0];
- *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+ *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
}
return 0;
}
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index b2ab8db439d9..532d0ae172d9 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -726,7 +726,7 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&inta->vint_list);
mutex_init(&inta->vint_mutex);
- dev_info(dev, "Interrupt Aggregator domain %d created\n", pdev->id);
+ dev_info(dev, "Interrupt Aggregator domain %d created\n", inta->ti_sci_id);
return 0;
}
diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c
index ac9d6d658e65..fe8fad22bcf9 100644
--- a/drivers/irqchip/irq-ti-sci-intr.c
+++ b/drivers/irqchip/irq-ti-sci-intr.c
@@ -129,7 +129,7 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
* @virq: Corresponding Linux virtual IRQ number
* @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
*
- * Returns parent irq if all went well else appropriate error pointer.
+ * Returns intr output irq if all went well else appropriate error pointer.
*/
static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
unsigned int virq, u32 hwirq)
@@ -173,7 +173,7 @@ static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
if (err)
goto err_msg;
- return p_hwirq;
+ return out_irq;
err_msg:
irq_domain_free_irqs_parent(domain, virq, 1);
@@ -198,19 +198,19 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
struct irq_fwspec *fwspec = data;
unsigned long hwirq;
unsigned int flags;
- int err, p_hwirq;
+ int err, out_irq;
err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
if (err)
return err;
- p_hwirq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq);
- if (p_hwirq < 0)
- return p_hwirq;
+ out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq);
+ if (out_irq < 0)
+ return out_irq;
irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
&ti_sci_intr_irq_chip,
- (void *)(uintptr_t)p_hwirq);
+ (void *)(uintptr_t)out_irq);
return 0;
}
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index bd39e9de6ecf..5dc63c20b67e 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -159,6 +159,8 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
{
int pin_out = d->hwirq;
enum pdc_irq_config_bits pdc_type;
+ enum pdc_irq_config_bits old_pdc_type;
+ int ret;
if (pin_out == GPIO_NO_WAKE_IRQ)
return 0;
@@ -187,9 +189,26 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
+ old_pdc_type = pdc_reg_read(IRQ_i_CFG, pin_out);
pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
- return irq_chip_set_type_parent(d, type);
+ ret = irq_chip_set_type_parent(d, type);
+ if (ret)
+ return ret;
+
+ /*
+ * When we change types the PDC can give a phantom interrupt.
+ * Clear it. Specifically the phantom shows up when reconfiguring
+ * polarity of interrupt without changing the state of the signal
+ * but let's be consistent and clear it always.
+ *
+ * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the
+ * interrupt will be cleared before the rest of the system sees it.
+ */
+ if (old_pdc_type != pdc_type)
+ irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false);
+
+ return 0;
}
static struct irq_chip qcom_pdc_gic_chip = {