diff options
Diffstat (limited to 'drivers/irqchip')
| -rw-r--r-- | drivers/irqchip/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/irqchip/irq-apple-aic.c | 6 | ||||
| -rw-r--r-- | drivers/irqchip/irq-gic-pm.c | 2 | ||||
| -rw-r--r-- | drivers/irqchip/irq-gic-v2m.c | 11 | ||||
| -rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 3 | ||||
| -rw-r--r-- | drivers/irqchip/irq-gic.c | 7 | ||||
| -rw-r--r-- | drivers/irqchip/irq-loongarch-cpu.c | 48 | ||||
| -rw-r--r-- | drivers/irqchip/irq-loongson-eiointc.c | 63 | ||||
| -rw-r--r-- | drivers/irqchip/irq-loongson-htvec.c | 176 | ||||
| -rw-r--r-- | drivers/irqchip/irq-loongson-liointc.c | 37 | ||||
| -rw-r--r-- | drivers/irqchip/irq-loongson-pch-lpc.c | 25 | ||||
| -rw-r--r-- | drivers/irqchip/irq-loongson-pch-pic.c | 76 | ||||
| -rw-r--r-- | drivers/irqchip/irq-ls-extirq.c | 2 | ||||
| -rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 2 | ||||
| -rw-r--r-- | drivers/irqchip/irq-mtk-cirq.c | 95 | ||||
| -rw-r--r-- | drivers/irqchip/irq-mvebu-icu.c | 4 | ||||
| -rw-r--r-- | drivers/irqchip/irq-sifive-plic.c | 6 | ||||
| -rw-r--r-- | drivers/irqchip/irq-sl28cpld.c | 3 | ||||
| -rw-r--r-- | drivers/irqchip/irq-st.c | 7 | ||||
| -rw-r--r-- | drivers/irqchip/irq-ti-sci-inta.c | 2 | ||||
| -rw-r--r-- | drivers/irqchip/irq-wpcm450-aic.c | 1 | 
21 files changed, 464 insertions, 121 deletions
| diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7ef9f5e696d3..d07568a2c539 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -38,7 +38,7 @@ config ARM_GIC_V3  config ARM_GIC_V3_ITS  	bool -	select GENERIC_MSI_IRQ_DOMAIN +	select GENERIC_MSI_IRQ  	default ARM_GIC_V3  config ARM_GIC_V3_ITS_PCI @@ -86,7 +86,7 @@ config ALPINE_MSI  config AL_FIC  	bool "Amazon's Annapurna Labs Fabric Interrupt Controller" -	depends on OF || COMPILE_TEST +	depends on OF  	select GENERIC_IRQ_CHIP  	select IRQ_DOMAIN  	help @@ -375,7 +375,7 @@ config MVEBU_ICU  config MVEBU_ODMI  	bool -	select GENERIC_MSI_IRQ_DOMAIN +	select GENERIC_MSI_IRQ  config MVEBU_PIC  	bool @@ -488,7 +488,7 @@ config IMX_MU_MSI  	default m if ARCH_MXC  	select IRQ_DOMAIN  	select IRQ_DOMAIN_HIERARCHY -	select GENERIC_MSI_IRQ_DOMAIN +	select GENERIC_MSI_IRQ  	help  	  Provide a driver for the i.MX Messaging Unit block used as a  	  CPU-to-CPU MSI controller. This requires a specially crafted DT @@ -576,6 +576,7 @@ config IRQ_LOONGARCH_CPU  	select GENERIC_IRQ_CHIP  	select IRQ_DOMAIN  	select GENERIC_IRQ_EFFECTIVE_AFF_MASK +	select LOONGSON_HTVEC  	select LOONGSON_LIOINTC  	select LOONGSON_EIOINTC  	select LOONGSON_PCH_PIC diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c index 1c2813ad8bbe..ae3437f03e6c 100644 --- a/drivers/irqchip/irq-apple-aic.c +++ b/drivers/irqchip/irq-apple-aic.c @@ -248,14 +248,14 @@ struct aic_info {  	bool fast_ipi;  }; -static const struct aic_info aic1_info = { +static const struct aic_info aic1_info __initconst = {  	.version	= 1,  	.event		= AIC_EVENT,  	.target_cpu	= AIC_TARGET_CPU,  }; -static const struct aic_info aic1_fipi_info = { +static const struct aic_info aic1_fipi_info __initconst = {  	.version	= 1,  	.event		= AIC_EVENT, @@ -264,7 +264,7 @@ static const struct aic_info aic1_fipi_info = {  	.fast_ipi	= true,  }; -static const struct aic_info aic2_info = { +static const struct aic_info aic2_info __initconst = {  	.version	= 2,  	.irq_cfg	= AIC2_IRQ_CFG, diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c index b60e1853593f..3989d16f997b 100644 --- a/drivers/irqchip/irq-gic-pm.c +++ b/drivers/irqchip/irq-gic-pm.c @@ -102,7 +102,7 @@ static int gic_probe(struct platform_device *pdev)  	pm_runtime_enable(dev); -	ret = pm_runtime_get_sync(dev); +	ret = pm_runtime_resume_and_get(dev);  	if (ret < 0)  		goto rpm_disable; diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 6e1ac330d7a6..f4d7eeb13951 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -24,6 +24,7 @@  #include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-common.h>  /*  * MSI_TYPER: @@ -262,7 +263,7 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = {  	.chip	= &gicv2m_pmsi_irq_chip,  }; -static void gicv2m_teardown(void) +static void __init gicv2m_teardown(void)  {  	struct v2m_data *v2m, *tmp; @@ -277,7 +278,7 @@ static void gicv2m_teardown(void)  	}  } -static int gicv2m_allocate_domains(struct irq_domain *parent) +static __init int gicv2m_allocate_domains(struct irq_domain *parent)  {  	struct irq_domain *inner_domain, *pci_domain, *plat_domain;  	struct v2m_data *v2m; @@ -404,7 +405,7 @@ err_free_v2m:  	return ret;  } -static const struct of_device_id gicv2m_device_id[] = { +static __initconst struct of_device_id gicv2m_device_id[] = {  	{	.compatible	= "arm,gic-v2m-frame",	},  	{},  }; @@ -454,7 +455,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,  #ifdef CONFIG_ACPI  static int acpi_num_msi; -static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) +static __init struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)  {  	struct v2m_data *data; @@ -469,7 +470,7 @@ static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)  	return data->fwnode;  } -static bool acpi_check_amazon_graviton_quirks(void) +static __init bool acpi_check_amazon_graviton_quirks(void)  {  	static struct acpi_table_madt *madt;  	acpi_status status; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 34d58567b78d..997104d4338e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -12,6 +12,7 @@  #include <linux/delay.h>  #include <linux/interrupt.h>  #include <linux/irqdomain.h> +#include <linux/kstrtox.h>  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/of_irq.h> @@ -1171,7 +1172,7 @@ static bool gicv3_nolpi;  static int __init gicv3_nolpi_cfg(char *buf)  { -	return strtobool(buf, &gicv3_nolpi); +	return kstrtobool(buf, &gicv3_nolpi);  }  early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4c7bae0ec8f9..210bc2f4d555 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -19,6 +19,7 @@   */  #include <linux/init.h>  #include <linux/kernel.h> +#include <linux/kstrtox.h>  #include <linux/err.h>  #include <linux/module.h>  #include <linux/list.h> @@ -401,8 +402,8 @@ static void gic_irq_print_chip(struct irq_data *d, struct seq_file *p)  {  	struct gic_chip_data *gic = irq_data_get_irq_chip_data(d); -	if (gic->domain->dev) -		seq_printf(p, gic->domain->dev->of_node->name); +	if (gic->domain->pm_dev) +		seq_printf(p, gic->domain->pm_dev->of_node->name);  	else  		seq_printf(p, "GIC-%d", (int)(gic - &gic_data[0]));  } @@ -1332,7 +1333,7 @@ static bool gicv2_force_probe;  static int __init gicv2_force_probe_cfg(char *buf)  { -	return strtobool(buf, &gicv2_force_probe); +	return kstrtobool(buf, &gicv2_force_probe);  }  early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg); diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c index 741612ba6a52..9d8f2c406043 100644 --- a/drivers/irqchip/irq-loongarch-cpu.c +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -92,18 +92,34 @@ static const struct irq_domain_ops loongarch_cpu_intc_irq_domain_ops = {  	.xlate = irq_domain_xlate_onecell,  }; -static int __init -liointc_parse_madt(union acpi_subtable_headers *header, -		       const unsigned long end) +#ifdef CONFIG_OF +static int __init cpuintc_of_init(struct device_node *of_node, +				struct device_node *parent) +{ +	cpuintc_handle = of_node_to_fwnode(of_node); + +	irq_domain = irq_domain_create_linear(cpuintc_handle, EXCCODE_INT_NUM, +				&loongarch_cpu_intc_irq_domain_ops, NULL); +	if (!irq_domain) +		panic("Failed to add irqdomain for loongarch CPU"); + +	set_handle_irq(&handle_cpu_irq); + +	return 0; +} +IRQCHIP_DECLARE(cpu_intc, "loongson,cpu-interrupt-controller", cpuintc_of_init); +#endif + +static int __init liointc_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end)  {  	struct acpi_madt_lio_pic *liointc_entry = (struct acpi_madt_lio_pic *)header;  	return liointc_acpi_init(irq_domain, liointc_entry);  } -static int __init -eiointc_parse_madt(union acpi_subtable_headers *header, -		       const unsigned long end) +static int __init eiointc_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end)  {  	struct acpi_madt_eio_pic *eiointc_entry = (struct acpi_madt_eio_pic *)header; @@ -112,16 +128,24 @@ eiointc_parse_madt(union acpi_subtable_headers *header,  static int __init acpi_cascade_irqdomain_init(void)  { -	acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, -			      liointc_parse_madt, 0); -	acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, -			      eiointc_parse_madt, 0); +	int r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_LIO_PIC, liointc_parse_madt, 0); +	if (r < 0) +		return r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC, eiointc_parse_madt, 0); +	if (r < 0) +		return r; +  	return 0;  }  static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,  				   const unsigned long end)  { +	int ret; +  	if (irq_domain)  		return 0; @@ -139,9 +163,9 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,  	set_handle_irq(&handle_cpu_irq);  	acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);  	acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq); -	acpi_cascade_irqdomain_init(); +	ret = acpi_cascade_irqdomain_init(); -	return 0; +	return ret;  }  IRQCHIP_ACPI_DECLARE(cpuintc_v1, ACPI_MADT_TYPE_CORE_PIC, diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index 16e9af8d8b1e..d15fd38c1756 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -17,6 +17,7 @@  #include <linux/of_address.h>  #include <linux/of_irq.h>  #include <linux/of_platform.h> +#include <linux/syscore_ops.h>  #define EIOINTC_REG_NODEMAP	0x14a0  #define EIOINTC_REG_IPMAP	0x14c0 @@ -301,9 +302,39 @@ static struct irq_domain *acpi_get_vec_parent(int node, struct acpi_vector_group  	return NULL;  } -static int __init -pch_pic_parse_madt(union acpi_subtable_headers *header, -		       const unsigned long end) +static int eiointc_suspend(void) +{ +	return 0; +} + +static void eiointc_resume(void) +{ +	int i, j; +	struct irq_desc *desc; +	struct irq_data *irq_data; + +	eiointc_router_init(0); + +	for (i = 0; i < nr_pics; i++) { +		for (j = 0; j < VEC_COUNT; j++) { +			desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j); +			if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) { +				raw_spin_lock(&desc->lock); +				irq_data = &desc->irq_data; +				eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0); +				raw_spin_unlock(&desc->lock); +			} +		} +	} +} + +static struct syscore_ops eiointc_syscore_ops = { +	.suspend = eiointc_suspend, +	.resume = eiointc_resume, +}; + +static int __init pch_pic_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end)  {  	struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header;  	unsigned int node = (pchpic_entry->address >> 44) & 0xf; @@ -315,9 +346,8 @@ pch_pic_parse_madt(union acpi_subtable_headers *header,  	return -EINVAL;  } -static int __init -pch_msi_parse_madt(union acpi_subtable_headers *header, -		       const unsigned long end) +static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end)  {  	struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header;  	struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group); @@ -330,17 +360,23 @@ pch_msi_parse_madt(union acpi_subtable_headers *header,  static int __init acpi_cascade_irqdomain_init(void)  { -	acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, -			      pch_pic_parse_madt, 0); -	acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, -			      pch_msi_parse_madt, 1); +	int r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0); +	if (r < 0) +		return r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1); +	if (r < 0) +		return r; +  	return 0;  }  int __init eiointc_acpi_init(struct irq_domain *parent,  				     struct acpi_madt_eio_pic *acpi_eiointc)  { -	int i, parent_irq; +	int i, ret, parent_irq;  	unsigned long node_map;  	struct eiointc_priv *priv; @@ -380,15 +416,16 @@ int __init eiointc_acpi_init(struct irq_domain *parent,  	parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);  	irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); +	register_syscore_ops(&eiointc_syscore_ops);  	cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,  				  "irqchip/loongarch/intc:starting",  				  eiointc_router_init, NULL);  	acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group);  	acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group); -	acpi_cascade_irqdomain_init(); +	ret = acpi_cascade_irqdomain_init(); -	return 0; +	return ret;  out_free_handle:  	irq_domain_free_fwnode(priv->domain_handle); diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c index 60a335d7e64e..fc8bf1f5d41b 100644 --- a/drivers/irqchip/irq-loongson-htvec.c +++ b/drivers/irqchip/irq-loongson-htvec.c @@ -16,11 +16,11 @@  #include <linux/of_address.h>  #include <linux/of_irq.h>  #include <linux/of_platform.h> +#include <linux/syscore_ops.h>  /* Registers */  #define HTVEC_EN_OFF		0x20  #define HTVEC_MAX_PARENT_IRQ	8 -  #define VEC_COUNT_PER_REG	32  #define VEC_REG_IDX(irq_id)	((irq_id) / VEC_COUNT_PER_REG)  #define VEC_REG_BIT(irq_id)	((irq_id) % VEC_COUNT_PER_REG) @@ -30,8 +30,11 @@ struct htvec {  	void __iomem		*base;  	struct irq_domain	*htvec_domain;  	raw_spinlock_t		htvec_lock; +	u32			saved_vec_en[HTVEC_MAX_PARENT_IRQ];  }; +static struct htvec *htvec_priv; +  static void htvec_irq_dispatch(struct irq_desc *desc)  {  	int i; @@ -155,64 +158,169 @@ static void htvec_reset(struct htvec *priv)  	}  } -static int htvec_of_init(struct device_node *node, -				struct device_node *parent) +static int htvec_suspend(void) +{ +	int i; + +	for (i = 0; i < htvec_priv->num_parents; i++) +		htvec_priv->saved_vec_en[i] = readl(htvec_priv->base + HTVEC_EN_OFF + 4 * i); + +	return 0; +} + +static void htvec_resume(void)  { +	int i; + +	for (i = 0; i < htvec_priv->num_parents; i++) +		writel(htvec_priv->saved_vec_en[i], htvec_priv->base + HTVEC_EN_OFF + 4 * i); +} + +static struct syscore_ops htvec_syscore_ops = { +	.suspend = htvec_suspend, +	.resume = htvec_resume, +}; + +static int htvec_init(phys_addr_t addr, unsigned long size, +		int num_parents, int parent_irq[], struct fwnode_handle *domain_handle) +{ +	int i;  	struct htvec *priv; -	int err, parent_irq[8], i;  	priv = kzalloc(sizeof(*priv), GFP_KERNEL);  	if (!priv)  		return -ENOMEM; +	priv->num_parents = num_parents; +	priv->base = ioremap(addr, size);  	raw_spin_lock_init(&priv->htvec_lock); -	priv->base = of_iomap(node, 0); -	if (!priv->base) { -		err = -ENOMEM; -		goto free_priv; -	} - -	/* Interrupt may come from any of the 8 interrupt lines */ -	for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) { -		parent_irq[i] = irq_of_parse_and_map(node, i); -		if (parent_irq[i] <= 0) -			break; -		priv->num_parents++; -	} - -	if (!priv->num_parents) { -		pr_err("Failed to get parent irqs\n"); -		err = -ENODEV; -		goto iounmap_base; -	} - -	priv->htvec_domain = irq_domain_create_linear(of_node_to_fwnode(node), +	/* Setup IRQ domain */ +	priv->htvec_domain = irq_domain_create_linear(domain_handle,  					(VEC_COUNT_PER_REG * priv->num_parents),  					&htvec_domain_ops, priv);  	if (!priv->htvec_domain) { -		pr_err("Failed to create IRQ domain\n"); -		err = -ENOMEM; -		goto irq_dispose; +		pr_err("loongson-htvec: cannot add IRQ domain\n"); +		goto iounmap_base;  	}  	htvec_reset(priv); -	for (i = 0; i < priv->num_parents; i++) +	for (i = 0; i < priv->num_parents; i++) {  		irq_set_chained_handler_and_data(parent_irq[i],  						 htvec_irq_dispatch, priv); +	} + +	htvec_priv = priv; + +	register_syscore_ops(&htvec_syscore_ops);  	return 0; -irq_dispose: -	for (; i > 0; i--) -		irq_dispose_mapping(parent_irq[i - 1]);  iounmap_base:  	iounmap(priv->base); -free_priv:  	kfree(priv); -	return err; +	return -EINVAL; +} + +#ifdef CONFIG_OF + +static int htvec_of_init(struct device_node *node, +				struct device_node *parent) +{ +	int i, err; +	int parent_irq[8]; +	int num_parents = 0; +	struct resource res; + +	if (of_address_to_resource(node, 0, &res)) +		return -EINVAL; + +	/* Interrupt may come from any of the 8 interrupt lines */ +	for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) { +		parent_irq[i] = irq_of_parse_and_map(node, i); +		if (parent_irq[i] <= 0) +			break; + +		num_parents++; +	} + +	err = htvec_init(res.start, resource_size(&res), +			num_parents, parent_irq, of_node_to_fwnode(node)); +	if (err < 0) +		return err; + +	return 0;  }  IRQCHIP_DECLARE(htvec, "loongson,htvec-1.0", htvec_of_init); + +#endif + +#ifdef CONFIG_ACPI +static int __init pch_pic_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end) +{ +	struct acpi_madt_bio_pic *pchpic_entry = (struct acpi_madt_bio_pic *)header; + +	return pch_pic_acpi_init(htvec_priv->htvec_domain, pchpic_entry); +} + +static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end) +{ +	struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; + +	return pch_msi_acpi_init(htvec_priv->htvec_domain, pchmsi_entry); +} + +static int __init acpi_cascade_irqdomain_init(void) +{ +	int r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_BIO_PIC, pch_pic_parse_madt, 0); +	if (r < 0) +		return r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 0); +	if (r < 0) +		return r; + +	return 0; +} + +int __init htvec_acpi_init(struct irq_domain *parent, +				   struct acpi_madt_ht_pic *acpi_htvec) +{ +	int i, ret; +	int num_parents, parent_irq[8]; +	struct fwnode_handle *domain_handle; + +	if (!acpi_htvec) +		return -EINVAL; + +	num_parents = HTVEC_MAX_PARENT_IRQ; + +	domain_handle = irq_domain_alloc_fwnode(&acpi_htvec->address); +	if (!domain_handle) { +		pr_err("Unable to allocate domain handle\n"); +		return -ENOMEM; +	} + +	/* Interrupt may come from any of the 8 interrupt lines */ +	for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) +		parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]); + +	ret = htvec_init(acpi_htvec->address, acpi_htvec->size, +			num_parents, parent_irq, domain_handle); + +	if (ret == 0) +		ret = acpi_cascade_irqdomain_init(); +	else +		irq_domain_free_fwnode(domain_handle); + +	return ret; +} + +#endif diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c index 0da8716f8f24..85b754f7f4e6 100644 --- a/drivers/irqchip/irq-loongson-liointc.c +++ b/drivers/irqchip/irq-loongson-liointc.c @@ -167,7 +167,12 @@ static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,  	if (WARN_ON(intsize < 1))  		return -EINVAL;  	*out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ; -	*out_type = IRQ_TYPE_NONE; + +	if (intsize > 1) +		*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; +	else +		*out_type = IRQ_TYPE_NONE; +  	return 0;  } @@ -207,10 +212,13 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,  					"reg-names", core_reg_names[i]);  			if (index < 0) -				goto out_iounmap; +				continue;  			priv->core_isr[i] = of_iomap(node, index);  		} + +		if (!priv->core_isr[0]) +			goto out_iounmap;  	}  	/* Setup IRQ domain */ @@ -349,6 +357,26 @@ IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init);  #endif  #ifdef CONFIG_ACPI +static int __init htintc_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end) +{ +	struct acpi_madt_ht_pic *htintc_entry = (struct acpi_madt_ht_pic *)header; +	struct irq_domain *parent = irq_find_matching_fwnode(liointc_handle, DOMAIN_BUS_ANY); + +	return htvec_acpi_init(parent, htintc_entry); +} + +static int __init acpi_cascade_irqdomain_init(void) +{ +	int r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_HT_PIC, htintc_parse_madt, 0); +	if (r < 0) +		return r; + +	return 0; +} +  int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc)  {  	int ret; @@ -365,9 +393,12 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic  		pr_err("Unable to allocate domain handle\n");  		return -ENOMEM;  	} +  	ret = liointc_init(acpi_liointc->address, acpi_liointc->size,  			   1, domain_handle, NULL); -	if (ret) +	if (ret == 0) +		ret = acpi_cascade_irqdomain_init(); +	else  		irq_domain_free_fwnode(domain_handle);  	return ret; diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c index bf2324910a75..9b35492fb6be 100644 --- a/drivers/irqchip/irq-loongson-pch-lpc.c +++ b/drivers/irqchip/irq-loongson-pch-lpc.c @@ -13,6 +13,7 @@  #include <linux/irqchip/chained_irq.h>  #include <linux/irqdomain.h>  #include <linux/kernel.h> +#include <linux/syscore_ops.h>  /* Registers */  #define LPC_INT_CTL		0x00 @@ -34,6 +35,7 @@ struct pch_lpc {  	u32			saved_reg_pol;  }; +static struct pch_lpc *pch_lpc_priv;  struct fwnode_handle *pch_lpc_handle;  static void lpc_irq_ack(struct irq_data *d) @@ -147,6 +149,26 @@ static int pch_lpc_disabled(struct pch_lpc *priv)  			(readl(priv->base + LPC_INT_STS) == 0xffffffff);  } +static int pch_lpc_suspend(void) +{ +	pch_lpc_priv->saved_reg_ctl = readl(pch_lpc_priv->base + LPC_INT_CTL); +	pch_lpc_priv->saved_reg_ena = readl(pch_lpc_priv->base + LPC_INT_ENA); +	pch_lpc_priv->saved_reg_pol = readl(pch_lpc_priv->base + LPC_INT_POL); +	return 0; +} + +static void pch_lpc_resume(void) +{ +	writel(pch_lpc_priv->saved_reg_ctl, pch_lpc_priv->base + LPC_INT_CTL); +	writel(pch_lpc_priv->saved_reg_ena, pch_lpc_priv->base + LPC_INT_ENA); +	writel(pch_lpc_priv->saved_reg_pol, pch_lpc_priv->base + LPC_INT_POL); +} + +static struct syscore_ops pch_lpc_syscore_ops = { +	.suspend = pch_lpc_suspend, +	.resume = pch_lpc_resume, +}; +  int __init pch_lpc_acpi_init(struct irq_domain *parent,  					struct acpi_madt_lpc_pic *acpi_pchlpc)  { @@ -191,7 +213,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent,  	parent_irq = irq_create_fwspec_mapping(&fwspec);  	irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv); +	pch_lpc_priv = priv;  	pch_lpc_handle = irq_handle; +	register_syscore_ops(&pch_lpc_syscore_ops); +  	return 0;  free_irq_handle: diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index c01b9c257005..437f1af693d0 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -15,6 +15,7 @@  #include <linux/of_address.h>  #include <linux/of_irq.h>  #include <linux/of_platform.h> +#include <linux/syscore_ops.h>  /* Registers */  #define PCH_PIC_MASK		0x20 @@ -42,6 +43,9 @@ struct pch_pic {  	raw_spinlock_t		pic_lock;  	u32			vec_count;  	u32			gsi_base; +	u32			saved_vec_en[PIC_REG_COUNT]; +	u32			saved_vec_pol[PIC_REG_COUNT]; +	u32			saved_vec_edge[PIC_REG_COUNT];  };  static struct pch_pic *pch_pic_priv[MAX_IO_PICS]; @@ -145,6 +149,7 @@ static struct irq_chip pch_pic_irq_chip = {  	.irq_ack		= pch_pic_ack_irq,  	.irq_set_affinity	= irq_chip_set_affinity_parent,  	.irq_set_type		= pch_pic_set_type, +	.flags			= IRQCHIP_SKIP_SET_WAKE,  };  static int pch_pic_domain_translate(struct irq_domain *d, @@ -155,15 +160,21 @@ static int pch_pic_domain_translate(struct irq_domain *d,  	struct pch_pic *priv = d->host_data;  	struct device_node *of_node = to_of_node(fwspec->fwnode); -	if (fwspec->param_count < 1) -		return -EINVAL; -  	if (of_node) { +		if (fwspec->param_count < 2) +			return -EINVAL; +  		*hwirq = fwspec->param[0] + priv->ht_vec_base;  		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;  	} else { +		if (fwspec->param_count < 1) +			return -EINVAL; +  		*hwirq = fwspec->param[0] - priv->gsi_base; -		*type = IRQ_TYPE_NONE; +		if (fwspec->param_count > 1) +			*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; +		else +			*type = IRQ_TYPE_NONE;  	}  	return 0; @@ -228,6 +239,46 @@ static void pch_pic_reset(struct pch_pic *priv)  	}  } +static int pch_pic_suspend(void) +{ +	int i, j; + +	for (i = 0; i < nr_pics; i++) { +		for (j = 0; j < PIC_REG_COUNT; j++) { +			pch_pic_priv[i]->saved_vec_pol[j] = +				readl(pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j); +			pch_pic_priv[i]->saved_vec_edge[j] = +				readl(pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j); +			pch_pic_priv[i]->saved_vec_en[j] = +				readl(pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j); +		} +	} + +	return 0; +} + +static void pch_pic_resume(void) +{ +	int i, j; + +	for (i = 0; i < nr_pics; i++) { +		pch_pic_reset(pch_pic_priv[i]); +		for (j = 0; j < PIC_REG_COUNT; j++) { +			writel(pch_pic_priv[i]->saved_vec_pol[j], +					pch_pic_priv[i]->base + PCH_PIC_POL + 4 * j); +			writel(pch_pic_priv[i]->saved_vec_edge[j], +					pch_pic_priv[i]->base + PCH_PIC_EDGE + 4 * j); +			writel(pch_pic_priv[i]->saved_vec_en[j], +					pch_pic_priv[i]->base + PCH_PIC_MASK + 4 * j); +		} +	} +} + +static struct syscore_ops pch_pic_syscore_ops = { +	.suspend =  pch_pic_suspend, +	.resume =  pch_pic_resume, +}; +  static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,  			struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,  			u32 gsi_base) @@ -260,6 +311,8 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,  	pch_pic_handle[nr_pics] = domain_handle;  	pch_pic_priv[nr_pics++] = priv; +	register_syscore_ops(&pch_pic_syscore_ops); +  	return 0;  iounmap_base: @@ -325,9 +378,8 @@ int find_pch_pic(u32 gsi)  	return -1;  } -static int __init -pch_lpc_parse_madt(union acpi_subtable_headers *header, -		       const unsigned long end) +static int __init pch_lpc_parse_madt(union acpi_subtable_headers *header, +					const unsigned long end)  {  	struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header; @@ -336,8 +388,12 @@ pch_lpc_parse_madt(union acpi_subtable_headers *header,  static int __init acpi_cascade_irqdomain_init(void)  { -	acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, -			      pch_lpc_parse_madt, 0); +	int r; + +	r = acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC, pch_lpc_parse_madt, 0); +	if (r < 0) +		return r; +  	return 0;  } @@ -364,7 +420,7 @@ int __init pch_pic_acpi_init(struct irq_domain *parent,  	}  	if (acpi_pchpic->id == 0) -		acpi_cascade_irqdomain_init(); +		ret = acpi_cascade_irqdomain_init();  	return ret;  } diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c index d8d48b1f7c29..139f26b0a6ef 100644 --- a/drivers/irqchip/irq-ls-extirq.c +++ b/drivers/irqchip/irq-ls-extirq.c @@ -203,7 +203,7 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)  	if (ret)  		goto err_parse_map; -	priv->big_endian = of_device_is_big_endian(parent); +	priv->big_endian = of_device_is_big_endian(node->parent);  	priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") ||  				      of_device_is_compatible(node, "fsl,ls1043a-extirq");  	raw_spin_lock_init(&priv->lock); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 1ba0f1555c80..1a6a7a672ad7 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -494,7 +494,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,  	map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin;  	/* -	 * If adding support for more per-cpu interrupts, keep the the +	 * If adding support for more per-cpu interrupts, keep the  	 * array in gic_all_vpes_irq_cpu_online() in sync.  	 */  	switch (intr) { diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c index 9bca0918078e..76bc0283e3b9 100644 --- a/drivers/irqchip/irq-mtk-cirq.c +++ b/drivers/irqchip/irq-mtk-cirq.c @@ -15,14 +15,41 @@  #include <linux/slab.h>  #include <linux/syscore_ops.h> -#define CIRQ_ACK	0x40 -#define CIRQ_MASK_SET	0xc0 -#define CIRQ_MASK_CLR	0x100 -#define CIRQ_SENS_SET	0x180 -#define CIRQ_SENS_CLR	0x1c0 -#define CIRQ_POL_SET	0x240 -#define CIRQ_POL_CLR	0x280 -#define CIRQ_CONTROL	0x300 +enum mtk_cirq_regoffs_index { +	CIRQ_STA, +	CIRQ_ACK, +	CIRQ_MASK_SET, +	CIRQ_MASK_CLR, +	CIRQ_SENS_SET, +	CIRQ_SENS_CLR, +	CIRQ_POL_SET, +	CIRQ_POL_CLR, +	CIRQ_CONTROL +}; + +static const u32 mtk_cirq_regoffs_v1[] = { +	[CIRQ_STA]	= 0x0, +	[CIRQ_ACK]	= 0x40, +	[CIRQ_MASK_SET]	= 0xc0, +	[CIRQ_MASK_CLR]	= 0x100, +	[CIRQ_SENS_SET]	= 0x180, +	[CIRQ_SENS_CLR]	= 0x1c0, +	[CIRQ_POL_SET]	= 0x240, +	[CIRQ_POL_CLR]	= 0x280, +	[CIRQ_CONTROL]	= 0x300, +}; + +static const u32 mtk_cirq_regoffs_v2[] = { +	[CIRQ_STA]	= 0x0, +	[CIRQ_ACK]	= 0x80, +	[CIRQ_MASK_SET]	= 0x180, +	[CIRQ_MASK_CLR]	= 0x200, +	[CIRQ_SENS_SET]	= 0x300, +	[CIRQ_SENS_CLR]	= 0x380, +	[CIRQ_POL_SET]	= 0x480, +	[CIRQ_POL_CLR]	= 0x500, +	[CIRQ_CONTROL]	= 0x600, +};  #define CIRQ_EN	0x1  #define CIRQ_EDGE	0x2 @@ -32,18 +59,32 @@ struct mtk_cirq_chip_data {  	void __iomem *base;  	unsigned int ext_irq_start;  	unsigned int ext_irq_end; +	const u32 *offsets;  	struct irq_domain *domain;  };  static struct mtk_cirq_chip_data *cirq_data; -static void mtk_cirq_write_mask(struct irq_data *data, unsigned int offset) +static void __iomem *mtk_cirq_reg(struct mtk_cirq_chip_data *chip_data, +				  enum mtk_cirq_regoffs_index idx) +{ +	return chip_data->base + chip_data->offsets[idx]; +} + +static void __iomem *mtk_cirq_irq_reg(struct mtk_cirq_chip_data *chip_data, +				      enum mtk_cirq_regoffs_index idx, +				      unsigned int cirq_num) +{ +	return mtk_cirq_reg(chip_data, idx) + (cirq_num / 32) * 4; +} + +static void mtk_cirq_write_mask(struct irq_data *data, enum mtk_cirq_regoffs_index idx)  {  	struct mtk_cirq_chip_data *chip_data = data->chip_data;  	unsigned int cirq_num = data->hwirq;  	u32 mask = 1 << (cirq_num % 32); -	writel_relaxed(mask, chip_data->base + offset + (cirq_num / 32) * 4); +	writel_relaxed(mask, mtk_cirq_irq_reg(chip_data, idx, cirq_num));  }  static void mtk_cirq_mask(struct irq_data *data) @@ -160,6 +201,7 @@ static const struct irq_domain_ops cirq_domain_ops = {  #ifdef CONFIG_PM_SLEEP  static int mtk_cirq_suspend(void)  { +	void __iomem *reg;  	u32 value, mask;  	unsigned int irq, hwirq_num;  	bool pending, masked; @@ -200,31 +242,34 @@ static int mtk_cirq_suspend(void)  				continue;  		} +		reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i);  		mask = 1 << (i % 32); -		writel_relaxed(mask, cirq_data->base + CIRQ_ACK + (i / 32) * 4); +		writel_relaxed(mask, reg);  	}  	/* set edge_only mode, record edge-triggerd interrupts */  	/* enable cirq */ -	value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); +	reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL); +	value = readl_relaxed(reg);  	value |= (CIRQ_EDGE | CIRQ_EN); -	writel_relaxed(value, cirq_data->base + CIRQ_CONTROL); +	writel_relaxed(value, reg);  	return 0;  }  static void mtk_cirq_resume(void)  { +	void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);  	u32 value;  	/* flush recorded interrupts, will send signals to parent controller */ -	value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); -	writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL); +	value = readl_relaxed(reg); +	writel_relaxed(value | CIRQ_FLUSH, reg);  	/* disable cirq */ -	value = readl_relaxed(cirq_data->base + CIRQ_CONTROL); +	value = readl_relaxed(reg);  	value &= ~(CIRQ_EDGE | CIRQ_EN); -	writel_relaxed(value, cirq_data->base + CIRQ_CONTROL); +	writel_relaxed(value, reg);  }  static struct syscore_ops mtk_cirq_syscore_ops = { @@ -240,10 +285,19 @@ static void mtk_cirq_syscore_init(void)  static inline void mtk_cirq_syscore_init(void) {}  #endif +static const struct of_device_id mtk_cirq_of_match[] = { +	{ .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 }, +	{ .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 }, +	{ .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 }, +	{ .compatible = "mediatek,mt8192-cirq", .data = &mtk_cirq_regoffs_v2 }, +	{ /* sentinel */ } +}; +  static int __init mtk_cirq_of_init(struct device_node *node,  				   struct device_node *parent)  {  	struct irq_domain *domain, *domain_parent; +	const struct of_device_id *match;  	unsigned int irq_num;  	int ret; @@ -274,6 +328,13 @@ static int __init mtk_cirq_of_init(struct device_node *node,  	if (ret)  		goto out_unmap; +	match = of_match_node(mtk_cirq_of_match, node); +	if (!match) { +		ret = -ENODEV; +		goto out_unmap; +	} +	cirq_data->offsets = match->data; +  	irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1;  	domain = irq_domain_add_hierarchy(domain_parent, 0,  					  irq_num, node, diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c index 497da344717c..3c77acc7ec6a 100644 --- a/drivers/irqchip/irq-mvebu-icu.c +++ b/drivers/irqchip/irq-mvebu-icu.c @@ -151,9 +151,9 @@ static int  mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,  			       unsigned long *hwirq, unsigned int *type)  { -	struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d); -	struct mvebu_icu *icu = platform_msi_get_host_data(d);  	unsigned int param_count = static_branch_unlikely(&legacy_bindings) ? 3 : 2; +	struct mvebu_icu_msi_data *msi_data = platform_msi_get_host_data(d); +	struct mvebu_icu *icu = msi_data->icu;  	/* Check the count of the parameters in dt */  	if (WARN_ON(fwspec->param_count != param_count)) { diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 2f4784860df5..ff47bd0dec45 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -187,7 +187,8 @@ static struct irq_chip plic_edge_chip = {  	.irq_set_affinity = plic_set_affinity,  #endif  	.irq_set_type	= plic_irq_set_type, -	.flags		= IRQCHIP_AFFINITY_PRE_STARTUP, +	.flags		= IRQCHIP_SKIP_SET_WAKE | +			  IRQCHIP_AFFINITY_PRE_STARTUP,  };  static struct irq_chip plic_chip = { @@ -201,7 +202,8 @@ static struct irq_chip plic_chip = {  	.irq_set_affinity = plic_set_affinity,  #endif  	.irq_set_type	= plic_irq_set_type, -	.flags		= IRQCHIP_AFFINITY_PRE_STARTUP, +	.flags		= IRQCHIP_SKIP_SET_WAKE | +			  IRQCHIP_AFFINITY_PRE_STARTUP,  };  static int plic_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/drivers/irqchip/irq-sl28cpld.c b/drivers/irqchip/irq-sl28cpld.c index fbb354413ffa..f2172240172c 100644 --- a/drivers/irqchip/irq-sl28cpld.c +++ b/drivers/irqchip/irq-sl28cpld.c @@ -65,8 +65,7 @@ static int sl28cpld_intc_probe(struct platform_device *pdev)  	irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs);  	irqchip->chip.num_regs = 1;  	irqchip->chip.status_base = base + INTC_IP; -	irqchip->chip.mask_base = base + INTC_IE; -	irqchip->chip.mask_invert = true; +	irqchip->chip.unmask_base = base + INTC_IE;  	irqchip->chip.ack_base = base + INTC_IP;  	return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev), diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c index 801551e46a7b..1b83512b29c6 100644 --- a/drivers/irqchip/irq-st.c +++ b/drivers/irqchip/irq-st.c @@ -153,18 +153,13 @@ static int st_irq_syscfg_enable(struct platform_device *pdev)  static int st_irq_syscfg_probe(struct platform_device *pdev)  {  	struct device_node *np = pdev->dev.of_node; -	const struct of_device_id *match;  	struct st_irq_syscfg *ddata;  	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);  	if (!ddata)  		return -ENOMEM; -	match = of_match_device(st_irq_syscfg_match, &pdev->dev); -	if (!match) -		return -ENODEV; - -	ddata->syscfg = (unsigned int)match->data; +	ddata->syscfg = (unsigned int) device_get_match_data(&pdev->dev);  	ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");  	if (IS_ERR(ddata->regmap)) { diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index 5fdbb4358dd0..a6ecc53d055c 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -168,7 +168,7 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)  /**   * ti_sci_inta_xlate_irq() - Translate hwirq to parent's hwirq.   * @inta:	IRQ domain corresponding to Interrupt Aggregator - * @irq:	Hardware irq corresponding to the above irq domain + * @vint_id:	Hardware irq corresponding to the above irq domain   *   * Return parent irq number if translation is available else -ENOENT.   */ diff --git a/drivers/irqchip/irq-wpcm450-aic.c b/drivers/irqchip/irq-wpcm450-aic.c index 0dcbeb1a05a1..91df62a64cd9 100644 --- a/drivers/irqchip/irq-wpcm450-aic.c +++ b/drivers/irqchip/irq-wpcm450-aic.c @@ -146,6 +146,7 @@ static int __init wpcm450_aic_of_init(struct device_node *node,  	aic->regs = of_iomap(node, 0);  	if (!aic->regs) {  		pr_err("Failed to map WPCM450 AIC registers\n"); +		kfree(aic);  		return -ENOMEM;  	} |