diff options
86 files changed, 1435 insertions, 2603 deletions
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt new file mode 100644 index 00000000000..27dcaabfb4d --- /dev/null +++ b/Documentation/IRQ-domain.txt @@ -0,0 +1,117 @@ +irq_domain interrupt number mapping library + +The current design of the Linux kernel uses a single large number +space where each separate IRQ source is assigned a different number. +This is simple when there is only one interrupt controller, but in +systems with multiple interrupt controllers the kernel must ensure +that each one gets assigned non-overlapping allocations of Linux +IRQ numbers. + +The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of +irq numbers, but they don't provide any support for reverse mapping of +the controller-local IRQ (hwirq) number into the Linux IRQ number +space. + +The irq_domain library adds mapping between hwirq and IRQ numbers on +top of the irq_alloc_desc*() API.  An irq_domain to manage mapping is +preferred over interrupt controller drivers open coding their own +reverse mapping scheme. + +irq_domain also implements translation from Device Tree interrupt +specifiers to hwirq numbers, and can be easily extended to support +other IRQ topology data sources. + +=== irq_domain usage === +An interrupt controller driver creates and registers an irq_domain by +calling one of the irq_domain_add_*() functions (each mapping method +has a different allocator function, more on that later).  The function +will return a pointer to the irq_domain on success.  The caller must +provide the allocator function with an irq_domain_ops structure with +the .map callback populated as a minimum. + +In most cases, the irq_domain will begin empty without any mappings +between hwirq and IRQ numbers.  Mappings are added to the irq_domain +by calling irq_create_mapping() which accepts the irq_domain and a +hwirq number as arguments.  If a mapping for the hwirq doesn't already +exist then it will allocate a new Linux irq_desc, associate it with +the hwirq, and call the .map() callback so the driver can perform any +required hardware setup. + +When an interrupt is received, irq_find_mapping() function should +be used to find the Linux IRQ number from the hwirq number. + +If the driver has the Linux IRQ number or the irq_data pointer, and +needs to know the associated hwirq number (such as in the irq_chip +callbacks) then it can be directly obtained from irq_data->hwirq. + +=== Types of irq_domain mappings === +There are several mechanisms available for reverse mapping from hwirq +to Linux irq, and each mechanism uses a different allocation function. +Which reverse map type should be used depends on the use case.  Each +of the reverse map types are described below: + +==== Linear ==== +irq_domain_add_linear() + +The linear reverse map maintains a fixed size table indexed by the +hwirq number.  When a hwirq is mapped, an irq_desc is allocated for +the hwirq, and the IRQ number is stored in the table. + +The Linear map is a good choice when the maximum number of hwirqs is +fixed and a relatively small number (~ < 256).  The advantages of this +map are fixed time lookup for IRQ numbers, and irq_descs are only +allocated for in-use IRQs.  The disadvantage is that the table must be +as large as the largest possible hwirq number. + +The majority of drivers should use the linear map. + +==== Tree ==== +irq_domain_add_tree() + +The irq_domain maintains a radix tree map from hwirq numbers to Linux +IRQs.  When an hwirq is mapped, an irq_desc is allocated and the +hwirq is used as the lookup key for the radix tree. + +The tree map is a good choice if the hwirq number can be very large +since it doesn't need to allocate a table as large as the largest +hwirq number.  The disadvantage is that hwirq to IRQ number lookup is +dependent on how many entries are in the table. + +Very few drivers should need this mapping.  At the moment, powerpc +iseries is the only user. + +==== No Map ===- +irq_domain_add_nomap() + +The No Map mapping is to be used when the hwirq number is +programmable in the hardware.  In this case it is best to program the +Linux IRQ number into the hardware itself so that no mapping is +required.  Calling irq_create_direct_mapping() will allocate a Linux +IRQ number and call the .map() callback so that driver can program the +Linux IRQ number into the hardware. + +Most drivers cannot use this mapping. + +==== Legacy ==== +irq_domain_add_legacy() +irq_domain_add_legacy_isa() + +The Legacy mapping is a special case for drivers that already have a +range of irq_descs allocated for the hwirqs.  It is used when the +driver cannot be immediately converted to use the linear mapping.  For +example, many embedded system board support files use a set of #defines +for IRQ numbers that are passed to struct device registrations.  In that +case the Linux IRQ numbers cannot be dynamically assigned and the legacy +mapping should be used. + +The legacy map assumes a contiguous range of IRQ numbers has already +been allocated for the controller and that the IRQ number can be +calculated by adding a fixed offset to the hwirq number, and +visa-versa.  The disadvantage is that it requires the interrupt +controller to manage IRQ allocations and it requires an irq_desc to be +allocated for every hwirq, even if it is unused. + +The legacy map should only be used if fixed IRQ mappings must be +supported.  For example, ISA controllers would use the legacy map for +mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ +numbers. diff --git a/MAINTAINERS b/MAINTAINERS index 9a648eb8e21..57dd0f56cd3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3640,6 +3640,15 @@ S:	Maintained  T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core  F:	kernel/irq/ +IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY) +M:	Benjamin Herrenschmidt <benh@kernel.crashing.org> +M:	Grant Likely <grant.likely@secretlab.ca> +T:	git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next +S:	Maintained +F:	Documentation/IRQ-domain.txt +F:	include/linux/irqdomain.h +F:	kernel/irq/irqdomain.c +  ISAPNP  M:	Jaroslav Kysela <perex@perex.cz>  S:	Maintained diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index c47d6199b78..f0783be1735 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -51,7 +51,6 @@ union gic_base {  };  struct gic_chip_data { -	unsigned int irq_offset;  	union gic_base dist_base;  	union gic_base cpu_base;  #ifdef CONFIG_CPU_PM @@ -61,9 +60,7 @@ struct gic_chip_data {  	u32 __percpu *saved_ppi_enable;  	u32 __percpu *saved_ppi_conf;  #endif -#ifdef CONFIG_IRQ_DOMAIN -	struct irq_domain domain; -#endif +	struct irq_domain *domain;  	unsigned int gic_irqs;  #ifdef CONFIG_GIC_NON_BANKED  	void __iomem *(*get_base)(union gic_base *); @@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)  		irqnr = irqstat & ~0x1c00;  		if (likely(irqnr > 15 && irqnr < 1021)) { -			irqnr = irq_domain_to_irq(&gic->domain, irqnr); +			irqnr = irq_find_mapping(gic->domain, irqnr);  			handle_IRQ(irqnr, regs);  			continue;  		} @@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)  	if (gic_irq == 1023)  		goto out; -	cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); -	if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) +	cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); +	if (unlikely(gic_irq < 32 || gic_irq > 1020))  		do_bad_IRQ(cascade_irq, desc);  	else  		generic_handle_irq(cascade_irq); @@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)  static void __init gic_dist_init(struct gic_chip_data *gic)  { -	unsigned int i, irq; +	unsigned int i;  	u32 cpumask;  	unsigned int gic_irqs = gic->gic_irqs; -	struct irq_domain *domain = &gic->domain;  	void __iomem *base = gic_data_dist_base(gic);  	u32 cpu = cpu_logical_map(smp_processor_id()); @@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)  	for (i = 32; i < gic_irqs; i += 32)  		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); -	/* -	 * Setup the Linux IRQ subsystem. -	 */ -	irq_domain_for_each_irq(domain, i, irq) { -		if (i < 32) { -			irq_set_percpu_devid(irq); -			irq_set_chip_and_handler(irq, &gic_chip, -						 handle_percpu_devid_irq); -			set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); -		} else { -			irq_set_chip_and_handler(irq, &gic_chip, -						 handle_fasteoi_irq); -			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); -		} -		irq_set_chip_data(irq, gic); -	} -  	writel_relaxed(1, base + GIC_DIST_CTRL);  } @@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic)  }  #endif -#ifdef CONFIG_OF -static int gic_irq_domain_dt_translate(struct irq_domain *d, -				       struct device_node *controller, -				       const u32 *intspec, unsigned int intsize, -				       unsigned long *out_hwirq, unsigned int *out_type) +static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, +				irq_hw_number_t hw) +{ +	if (hw < 32) { +		irq_set_percpu_devid(irq); +		irq_set_chip_and_handler(irq, &gic_chip, +					 handle_percpu_devid_irq); +		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); +	} else { +		irq_set_chip_and_handler(irq, &gic_chip, +					 handle_fasteoi_irq); +		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); +	} +	irq_set_chip_data(irq, d->host_data); +	return 0; +} + +static int gic_irq_domain_xlate(struct irq_domain *d, +				struct device_node *controller, +				const u32 *intspec, unsigned int intsize, +				unsigned long *out_hwirq, unsigned int *out_type)  {  	if (d->of_node != controller)  		return -EINVAL; @@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d,  	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;  	return 0;  } -#endif  const struct irq_domain_ops gic_irq_domain_ops = { -#ifdef CONFIG_OF -	.dt_translate = gic_irq_domain_dt_translate, -#endif +	.map = gic_irq_domain_map, +	.xlate = gic_irq_domain_xlate,  };  void __init gic_init_bases(unsigned int gic_nr, int irq_start,  			   void __iomem *dist_base, void __iomem *cpu_base, -			   u32 percpu_offset) +			   u32 percpu_offset, struct device_node *node)  { +	irq_hw_number_t hwirq_base;  	struct gic_chip_data *gic; -	struct irq_domain *domain; -	int gic_irqs; +	int gic_irqs, irq_base;  	BUG_ON(gic_nr >= MAX_GIC_NR);  	gic = &gic_data[gic_nr]; -	domain = &gic->domain;  #ifdef CONFIG_GIC_NON_BANKED  	if (percpu_offset) { /* Frankein-GIC without banked registers... */  		unsigned int cpu; @@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,  	 * For primary GICs, skip over SGIs.  	 * For secondary GICs, skip over PPIs, too.  	 */ -	domain->hwirq_base = 32; +	hwirq_base = 32;  	if (gic_nr == 0) {  		if ((irq_start & 31) > 0) { -			domain->hwirq_base = 16; +			hwirq_base = 16;  			if (irq_start != -1)  				irq_start = (irq_start & ~31) + 16;  		} @@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,  		gic_irqs = 1020;  	gic->gic_irqs = gic_irqs; -	domain->nr_irq = gic_irqs - domain->hwirq_base; -	domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, -					   numa_node_id()); -	if (IS_ERR_VALUE(domain->irq_base)) { +	gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ +	irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); +	if (IS_ERR_VALUE(irq_base)) {  		WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",  		     irq_start); -		domain->irq_base = irq_start; +		irq_base = irq_start;  	} -	domain->priv = gic; -	domain->ops = &gic_irq_domain_ops; -	irq_domain_add(domain); +	gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, +				    hwirq_base, &gic_irq_domain_ops, gic); +	if (WARN_ON(!gic->domain)) +		return;  	gic_chip.flags |= gic_arch_extn.flags;  	gic_dist_init(gic); @@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)  	void __iomem *dist_base;  	u32 percpu_offset;  	int irq; -	struct irq_domain *domain = &gic_data[gic_cnt].domain;  	if (WARN_ON(!node))  		return -ENODEV; @@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)  	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))  		percpu_offset = 0; -	domain->of_node = of_node_get(node); - -	gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset); +	gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);  	if (parent) {  		irq = irq_of_parse_and_map(node, 0); diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index dcb004a804c..7a66311f306 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -56,7 +56,7 @@ struct vic_device {  	u32		int_enable;  	u32		soft_int;  	u32		protect; -	struct irq_domain domain; +	struct irq_domain *domain;  };  /* we cannot allocate memory when VICs are initially registered */ @@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq,  	v->resume_sources = resume_sources;  	v->irq = irq;  	vic_id++; - -	v->domain.irq_base = irq; -	v->domain.nr_irq = 32; -#ifdef CONFIG_OF_IRQ -	v->domain.of_node = of_node_get(node); -#endif /* CONFIG_OF */ -	v->domain.ops = &irq_domain_simple_ops; -	irq_domain_add(&v->domain); +	v->domain = irq_domain_add_legacy(node, 32, irq, 0, +					  &irq_domain_simple_ops, v);  }  static void vic_ack_irq(struct irq_data *d) @@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,  	vic_register(base, irq_start, 0, node);  } -static void __init __vic_init(void __iomem *base, unsigned int irq_start, +void __init __vic_init(void __iomem *base, unsigned int irq_start,  			      u32 vic_sources, u32 resume_sources,  			      struct device_node *node)  { @@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)  	stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);  	while (stat) {  		irq = ffs(stat) - 1; -		handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs); +		handle_IRQ(irq_find_mapping(vic->domain, irq), regs);  		stat &= ~(1 << irq);  		handled = 1;  	} diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 4bdfe001869..4b1ce6cd477 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -39,7 +39,7 @@ struct device_node;  extern struct irq_chip gic_arch_extn;  void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, -		    u32 offset); +		    u32 offset, struct device_node *);  int gic_of_init(struct device_node *node, struct device_node *parent);  void gic_secondary_init(unsigned int);  void gic_handle_irq(struct pt_regs *regs); @@ -49,7 +49,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);  static inline void gic_init(unsigned int nr, int start,  			    void __iomem *dist , void __iomem *cpu)  { -	gic_init_bases(nr, start, dist, cpu, 0); +	gic_init_bases(nr, start, dist, cpu, 0, NULL);  }  #endif diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index f42ebd61959..e14af1a1a32 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h @@ -47,6 +47,8 @@  struct device_node;  struct pt_regs; +void __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, +		u32 resume_sources, struct device_node *node);  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);  int vic_of_init(struct device_node *node, struct device_node *parent);  void vic_handle_irq(struct pt_regs *regs); diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index c59e1887100..6de298c5d2d 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -402,7 +402,7 @@ void __init exynos4_init_irq(void)  	gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;  	if (!of_have_populated_dt()) -		gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset); +		gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);  #ifdef CONFIG_OF  	else  		of_irq_init(exynos4_dt_irq_match); diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index e6bad17b908..1e03ef42faa 100644 --- a/arch/arm/mach-imx/imx51-dt.c +++ b/arch/arm/mach-imx/imx51-dt.c @@ -47,7 +47,7 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = {  static int __init imx51_tzic_add_irq_domain(struct device_node *np,  				struct device_node *interrupt_parent)  { -	irq_domain_add_simple(np, 0); +	irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);  	return 0;  } @@ -57,7 +57,7 @@ static int __init imx51_gpio_add_irq_domain(struct device_node *np,  	static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;  	gpio_irq_base -= 32; -	irq_domain_add_simple(np, gpio_irq_base); +	irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);  	return 0;  } diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c index 05ebb3e6867..fd5be0f20fb 100644 --- a/arch/arm/mach-imx/imx53-dt.c +++ b/arch/arm/mach-imx/imx53-dt.c @@ -51,7 +51,7 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = {  static int __init imx53_tzic_add_irq_domain(struct device_node *np,  				struct device_node *interrupt_parent)  { -	irq_domain_add_simple(np, 0); +	irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);  	return 0;  } @@ -61,7 +61,7 @@ static int __init imx53_gpio_add_irq_domain(struct device_node *np,  	static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;  	gpio_irq_base -= 32; -	irq_domain_add_simple(np, gpio_irq_base); +	irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);  	return 0;  } diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index c2572810691..6075d4d62dd 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -97,7 +97,8 @@ static int __init imx6q_gpio_add_irq_domain(struct device_node *np,  	static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS;  	gpio_irq_base -= 32; -	irq_domain_add_simple(np, gpio_irq_base); +	irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, +			      NULL);  	return 0;  } diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index 0a113424632..962e7116975 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -80,12 +80,8 @@ static struct of_device_id msm_dt_gic_match[] __initdata = {  static void __init msm8x60_dt_init(void)  { -	struct device_node *node; - -	node = of_find_matching_node_by_address(NULL, msm_dt_gic_match, -			MSM8X60_QGIC_DIST_PHYS); -	if (node) -		irq_domain_add_simple(node, GIC_SPI_START); +	irq_domain_generate_simple(msm_dt_gic_match, MSM8X60_QGIC_DIST_PHYS, +				GIC_SPI_START);  	if (of_machine_is_compatible("qcom,msm8660-surf")) {  		printk(KERN_INFO "Init surf UART registers\n"); diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index d32b5935233..02d7e828a14 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -68,7 +68,7 @@ static void __init omap_generic_init(void)  {  	struct device_node *node = of_find_matching_node(NULL, intc_match);  	if (node) -		irq_domain_add_simple(node, 0); +		irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL);  	omap_sdrc_init(NULL, NULL); diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index d93ceef4a50..37c2de9b6f2 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -68,7 +68,7 @@ void __init sirfsoc_of_irq_init(void)  	if (!sirfsoc_intc_base)  		panic("unable to map intc cpu registers\n"); -	irq_domain_add_simple(np, 0); +	irq_domain_add_legacy(np, 32, 0, 0, &irq_domain_simple_ops, NULL);  	of_node_put(np); diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 02b7b9303f3..008ce22b9a0 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -98,8 +98,11 @@ static const struct of_device_id sic_of_match[] __initconst = {  void __init versatile_init_irq(void)  { -	vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0); -	irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START); +	struct device_node *np; + +	np = of_find_matching_node_by_address(NULL, vic_of_match, +					      VERSATILE_VIC_BASE); +	__vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np);  	writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index 26e67f0f005..3c64b2894c1 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig @@ -12,6 +12,7 @@ config TMS320C6X  	select HAVE_GENERIC_HARDIRQS  	select HAVE_MEMBLOCK  	select HAVE_SPARSE_IRQ +	select IRQ_DOMAIN  	select OF  	select OF_EARLY_FLATTREE diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h index a6ae3c9d9c4..f13b78d5e1c 100644 --- a/arch/c6x/include/asm/irq.h +++ b/arch/c6x/include/asm/irq.h @@ -13,6 +13,7 @@  #ifndef _ASM_C6X_IRQ_H  #define _ASM_C6X_IRQ_H +#include <linux/irqdomain.h>  #include <linux/threads.h>  #include <linux/list.h>  #include <linux/radix-tree.h> @@ -41,253 +42,9 @@  /* This number is used when no interrupt has been assigned */  #define NO_IRQ		0 -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -/* Interrupt controller "host" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The host - * structure is generally created by the PIC code for a given PIC instance - * (though a host can cover more than one PIC if they have a flat number - * model). It's the host callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures are fairly agnostic to the fact that - * we use an open firmware device-tree. We do have references to struct - * device_node in two places: in irq_find_host() to find the host matching - * a given interrupt controller node, and of course as an argument to its - * counterpart host->ops->match() callback. However, those are treated as - * generic pointers by the core and the fact that it's actually a device-node - * pointer is purely a convention between callers and implementation. This - * code could thus be used on other architectures by replacing those two - * by some sort of arch-specific void * "token" used to identify interrupt - * controllers. - */ -struct irq_host; -struct radix_tree_root; -struct device_node; - -/* Functions below are provided by the host and called whenever a new mapping - * is created or an old mapping is disposed. The host can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_host_ops { -	/* Match an interrupt controller device node to a host, returns -	 * 1 on a match -	 */ -	int (*match)(struct irq_host *h, struct device_node *node); - -	/* Create or update a mapping between a virtual irq number and a hw -	 * irq number. This is called only once for a given mapping. -	 */ -	int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - -	/* Dispose of such a mapping */ -	void (*unmap)(struct irq_host *h, unsigned int virq); - -	/* Translate device-tree interrupt specifier from raw format coming -	 * from the firmware to a irq_hw_number_t (interrupt line number) and -	 * type (sense) that can be passed to set_irq_type(). In the absence -	 * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() -	 * will return the hw number in the first cell and IRQ_TYPE_NONE for -	 * the type (which amount to keeping whatever default value the -	 * interrupt controller has for that line) -	 */ -	int (*xlate)(struct irq_host *h, struct device_node *ctrler, -		     const u32 *intspec, unsigned int intsize, -		     irq_hw_number_t *out_hwirq, unsigned int *out_type); -}; - -struct irq_host { -	struct list_head	link; - -	/* type of reverse mapping technique */ -	unsigned int		revmap_type; -#define IRQ_HOST_MAP_PRIORITY   0 /* core priority irqs, get irqs 1..15 */ -#define IRQ_HOST_MAP_NOMAP	1 /* no fast reverse mapping */ -#define IRQ_HOST_MAP_LINEAR	2 /* linear map of interrupts */ -#define IRQ_HOST_MAP_TREE	3 /* radix tree */ -	union { -		struct { -			unsigned int size; -			unsigned int *revmap; -		} linear; -		struct radix_tree_root tree; -	} revmap_data; -	struct irq_host_ops	*ops; -	void			*host_data; -	irq_hw_number_t		inval_irq; - -	/* Optional device node pointer */ -	struct device_node	*of_node; -}; -  struct irq_data;  extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);  extern irq_hw_number_t virq_to_hw(unsigned int virq); -extern bool virq_is_host(unsigned int virq, struct irq_host *host); - -/** - * irq_alloc_host - Allocate a new irq_host data structure - * @of_node: optional device-tree node of the interrupt controller - * @revmap_type: type of reverse mapping to use - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map - * @ops: map/unmap host callbacks - * @inval_irq: provide a hw number in that host space that is always invalid - * - * Allocates and initialize and irq_host structure. Note that in the case of - * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns - * for all legacy interrupts except 0 (which is always the invalid irq for - * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated - * later during boot automatically (the reverse mapping will use the slow path - * until that happens). - */ -extern struct irq_host *irq_alloc_host(struct device_node *of_node, -				       unsigned int revmap_type, -				       unsigned int revmap_arg, -				       struct irq_host_ops *ops, -				       irq_hw_number_t inval_irq); - - -/** - * irq_find_host - Locates a host for a given device node - * @node: device-tree node of the interrupt controller - */ -extern struct irq_host *irq_find_host(struct device_node *node); - - -/** - * irq_set_default_host - Set a "default" host - * @host: default host pointer - * - * For convenience, it's possible to set a "default" host that will be used - * whenever NULL is passed to irq_create_mapping(). It makes life easier for - * platforms that want to manipulate a few hard coded interrupt numbers that - * aren't properly represented in the device-tree. - */ -extern void irq_set_default_host(struct irq_host *host); - - -/** - * irq_set_virq_count - Set the maximum number of virt irqs - * @count: number of linux virtual irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -extern void irq_set_virq_count(unsigned int count); - - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, -				       irq_hw_number_t hwirq); - - -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_find_mapping - Find a linux virq from an hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a slow path, for use by generic code. It's expected that an - * irq controller implementation directly calls the appropriate low level - * mapping function. - */ -extern unsigned int irq_find_mapping(struct irq_host *host, -				     irq_hw_number_t hwirq); - -/** - * irq_create_direct_mapping - Allocate a virq for direct mapping - * @host: host to allocate the virq for or NULL for default host - * - * This routine is used for irq controllers which can choose the hardware - * interrupt numbers they generate. In such a case it's simplest to use - * the linux virq as the hardware interrupt number. - */ -extern unsigned int irq_create_direct_mapping(struct irq_host *host); - -/** - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. - * @host: host owning this hardware interrupt - * @virq: linux irq number - * @hwirq: hardware irq number in that host space - * - * This is for use by irq controllers that use a radix tree reverse - * mapping for fast lookup. - */ -extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, -				    irq_hw_number_t hwirq); - -/** - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses radix tree - * revmaps - */ -extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, -					    irq_hw_number_t hwirq); - -/** - * irq_linear_revmap - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses linear - * revmaps. It does fallback to the slow path if the revmap doesn't exist - * yet and will create the revmap entry with appropriate locking - */ - -extern unsigned int irq_linear_revmap(struct irq_host *host, -				      irq_hw_number_t hwirq); - - - -/** - * irq_alloc_virt - Allocate virtual irq numbers - * @host: host owning these new virtual irqs - * @count: number of consecutive numbers to allocate - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping - * - * This is a low level function that is used internally by irq_create_mapping() - * and that can be used by some irq controllers implementations for things - * like allocating ranges of numbers for MSIs. The revmaps are left untouched. - */ -extern unsigned int irq_alloc_virt(struct irq_host *host, -				   unsigned int count, -				   unsigned int hint); - -/** - * irq_free_virt - Free virtual irq numbers - * @virq: virtual irq number of the first interrupt to free - * @count: number of interrupts to free - * - * This function is the opposite of irq_alloc_virt. It will not clear reverse - * maps, this should be done previously by unmap'ing the interrupt. In fact, - * all interrupts covered by the range being freed should have been unmapped - * prior to calling this. - */ -extern void irq_free_virt(unsigned int virq, unsigned int count);  extern void __init init_pic_c64xplus(void); diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c index 0929e4b2b24..d77bcfdf0d8 100644 --- a/arch/c6x/kernel/irq.c +++ b/arch/c6x/kernel/irq.c @@ -73,10 +73,10 @@ asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)  	set_irq_regs(old_regs);  } -static struct irq_host *core_host; +static struct irq_domain *core_domain; -static int core_host_map(struct irq_host *h, unsigned int virq, -			 irq_hw_number_t hw) +static int core_domain_map(struct irq_domain *h, unsigned int virq, +			   irq_hw_number_t hw)  {  	if (hw < 4 || hw >= NR_PRIORITY_IRQS)  		return -EINVAL; @@ -86,8 +86,9 @@ static int core_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops core_host_ops = { -	.map = core_host_map, +static const struct irq_domain_ops core_domain_ops = { +	.map = core_domain_map, +	.xlate = irq_domain_xlate_onecell,  };  void __init init_IRQ(void) @@ -100,10 +101,11 @@ void __init init_IRQ(void)  	np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");  	if (np != NULL) {  		/* create the core host */ -		core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0, -					   &core_host_ops, 0); -		if (core_host) -			irq_set_default_host(core_host); +		core_domain = irq_domain_add_legacy(np, NR_PRIORITY_IRQS, +						    0, 0, &core_domain_ops, +						    NULL); +		if (core_domain) +			irq_set_default_host(core_domain);  		of_node_put(np);  	} @@ -128,601 +130,15 @@ int arch_show_interrupts(struct seq_file *p, int prec)  	return 0;  } -/* - * IRQ controller and virtual interrupts - */ - -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { -	irq_hw_number_t	hwirq; -	struct irq_host	*host; -}; - -static LIST_HEAD(irq_hosts); -static DEFINE_RAW_SPINLOCK(irq_big_lock); -static DEFINE_MUTEX(revmap_trees_mutex); -static struct irq_map_entry irq_map[NR_IRQS]; -static unsigned int irq_virq_count = NR_IRQS; -static struct irq_host *irq_default_host; -  irq_hw_number_t irqd_to_hwirq(struct irq_data *d)  { -	return irq_map[d->irq].hwirq; +	return d->hwirq;  }  EXPORT_SYMBOL_GPL(irqd_to_hwirq);  irq_hw_number_t virq_to_hw(unsigned int virq)  { -	return irq_map[virq].hwirq; +	struct irq_data *irq_data = irq_get_irq_data(virq); +	return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;  }  EXPORT_SYMBOL_GPL(virq_to_hw); - -bool virq_is_host(unsigned int virq, struct irq_host *host) -{ -	return irq_map[virq].host == host; -} -EXPORT_SYMBOL_GPL(virq_is_host); - -static int default_irq_host_match(struct irq_host *h, struct device_node *np) -{ -	return h->of_node != NULL && h->of_node == np; -} - -struct irq_host *irq_alloc_host(struct device_node *of_node, -				unsigned int revmap_type, -				unsigned int revmap_arg, -				struct irq_host_ops *ops, -				irq_hw_number_t inval_irq) -{ -	struct irq_host *host; -	unsigned int size = sizeof(struct irq_host); -	unsigned int i; -	unsigned int *rmap; -	unsigned long flags; - -	/* Allocate structure and revmap table if using linear mapping */ -	if (revmap_type == IRQ_HOST_MAP_LINEAR) -		size += revmap_arg * sizeof(unsigned int); -	host = kzalloc(size, GFP_KERNEL); -	if (host == NULL) -		return NULL; - -	/* Fill structure */ -	host->revmap_type = revmap_type; -	host->inval_irq = inval_irq; -	host->ops = ops; -	host->of_node = of_node_get(of_node); - -	if (host->ops->match == NULL) -		host->ops->match = default_irq_host_match; - -	raw_spin_lock_irqsave(&irq_big_lock, flags); - -	/* Check for the priority controller. */ -	if (revmap_type == IRQ_HOST_MAP_PRIORITY) { -		if (irq_map[0].host != NULL) { -			raw_spin_unlock_irqrestore(&irq_big_lock, flags); -			of_node_put(host->of_node); -			kfree(host); -			return NULL; -		} -		irq_map[0].host = host; -	} - -	list_add(&host->link, &irq_hosts); -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); - -	/* Additional setups per revmap type */ -	switch (revmap_type) { -	case IRQ_HOST_MAP_PRIORITY: -		/* 0 is always the invalid number for priority */ -		host->inval_irq = 0; -		/* setup us as the host for all priority interrupts */ -		for (i = 1; i < NR_PRIORITY_IRQS; i++) { -			irq_map[i].hwirq = i; -			smp_wmb(); -			irq_map[i].host = host; -			smp_wmb(); - -			ops->map(host, i, i); -		} -		break; -	case IRQ_HOST_MAP_LINEAR: -		rmap = (unsigned int *)(host + 1); -		for (i = 0; i < revmap_arg; i++) -			rmap[i] = NO_IRQ; -		host->revmap_data.linear.size = revmap_arg; -		smp_wmb(); -		host->revmap_data.linear.revmap = rmap; -		break; -	case IRQ_HOST_MAP_TREE: -		INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); -		break; -	default: -		break; -	} - -	pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); - -	return host; -} - -struct irq_host *irq_find_host(struct device_node *node) -{ -	struct irq_host *h, *found = NULL; -	unsigned long flags; - -	/* We might want to match the legacy controller last since -	 * it might potentially be set to match all interrupts in -	 * the absence of a device node. This isn't a problem so far -	 * yet though... -	 */ -	raw_spin_lock_irqsave(&irq_big_lock, flags); -	list_for_each_entry(h, &irq_hosts, link) -		if (h->ops->match(h, node)) { -			found = h; -			break; -		} -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); -	return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_host *host) -{ -	pr_debug("irq: Default host set to @0x%p\n", host); - -	irq_default_host = host; -} - -void irq_set_virq_count(unsigned int count) -{ -	pr_debug("irq: Trying to set virq count to %d\n", count); - -	BUG_ON(count < NR_PRIORITY_IRQS); -	if (count < NR_IRQS) -		irq_virq_count = count; -} - -static int irq_setup_virq(struct irq_host *host, unsigned int virq, -			    irq_hw_number_t hwirq) -{ -	int res; - -	res = irq_alloc_desc_at(virq, 0); -	if (res != virq) { -		pr_debug("irq: -> allocating desc failed\n"); -		goto error; -	} - -	/* map it */ -	smp_wmb(); -	irq_map[virq].hwirq = hwirq; -	smp_mb(); - -	if (host->ops->map(host, virq, hwirq)) { -		pr_debug("irq: -> mapping failed, freeing\n"); -		goto errdesc; -	} - -	irq_clear_status_flags(virq, IRQ_NOREQUEST); - -	return 0; - -errdesc: -	irq_free_descs(virq, 1); -error: -	irq_free_virt(virq, 1); -	return -1; -} - -unsigned int irq_create_direct_mapping(struct irq_host *host) -{ -	unsigned int virq; - -	if (host == NULL) -		host = irq_default_host; - -	BUG_ON(host == NULL); -	WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); - -	virq = irq_alloc_virt(host, 1, 0); -	if (virq == NO_IRQ) { -		pr_debug("irq: create_direct virq allocation failed\n"); -		return NO_IRQ; -	} - -	pr_debug("irq: create_direct obtained virq %d\n", virq); - -	if (irq_setup_virq(host, virq, virq)) -		return NO_IRQ; - -	return virq; -} - -unsigned int irq_create_mapping(struct irq_host *host, -				irq_hw_number_t hwirq) -{ -	unsigned int virq, hint; - -	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); - -	/* Look for default host if nececssary */ -	if (host == NULL) -		host = irq_default_host; -	if (host == NULL) { -		printk(KERN_WARNING "irq_create_mapping called for" -		       " NULL host, hwirq=%lx\n", hwirq); -		WARN_ON(1); -		return NO_IRQ; -	} -	pr_debug("irq: -> using host @%p\n", host); - -	/* Check if mapping already exists */ -	virq = irq_find_mapping(host, hwirq); -	if (virq != NO_IRQ) { -		pr_debug("irq: -> existing mapping on virq %d\n", virq); -		return virq; -	} - -	/* Allocate a virtual interrupt number */ -	hint = hwirq % irq_virq_count; -	virq = irq_alloc_virt(host, 1, hint); -	if (virq == NO_IRQ) { -		pr_debug("irq: -> virq allocation failed\n"); -		return NO_IRQ; -	} - -	if (irq_setup_virq(host, virq, hwirq)) -		return NO_IRQ; - -	pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", -		hwirq, host->of_node ? host->of_node->full_name : "null", virq); - -	return virq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, -				   const u32 *intspec, unsigned int intsize) -{ -	struct irq_host *host; -	irq_hw_number_t hwirq; -	unsigned int type = IRQ_TYPE_NONE; -	unsigned int virq; - -	if (controller == NULL) -		host = irq_default_host; -	else -		host = irq_find_host(controller); -	if (host == NULL) { -		printk(KERN_WARNING "irq: no irq host found for %s !\n", -		       controller->full_name); -		return NO_IRQ; -	} - -	/* If host has no translation, then we assume interrupt line */ -	if (host->ops->xlate == NULL) -		hwirq = intspec[0]; -	else { -		if (host->ops->xlate(host, controller, intspec, intsize, -				     &hwirq, &type)) -			return NO_IRQ; -	} - -	/* Create mapping */ -	virq = irq_create_mapping(host, hwirq); -	if (virq == NO_IRQ) -		return virq; - -	/* Set type if specified and different than the current one */ -	if (type != IRQ_TYPE_NONE && -	    type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) -		irq_set_irq_type(virq, type); -	return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - -void irq_dispose_mapping(unsigned int virq) -{ -	struct irq_host *host; -	irq_hw_number_t hwirq; - -	if (virq == NO_IRQ) -		return; - -	/* Never unmap priority interrupts */ -	if (virq < NR_PRIORITY_IRQS) -		return; - -	host = irq_map[virq].host; -	if (WARN_ON(host == NULL)) -		return; - -	irq_set_status_flags(virq, IRQ_NOREQUEST); - -	/* remove chip and handler */ -	irq_set_chip_and_handler(virq, NULL, NULL); - -	/* Make sure it's completed */ -	synchronize_irq(virq); - -	/* Tell the PIC about it */ -	if (host->ops->unmap) -		host->ops->unmap(host, virq); -	smp_mb(); - -	/* Clear reverse map */ -	hwirq = irq_map[virq].hwirq; -	switch (host->revmap_type) { -	case IRQ_HOST_MAP_LINEAR: -		if (hwirq < host->revmap_data.linear.size) -			host->revmap_data.linear.revmap[hwirq] = NO_IRQ; -		break; -	case IRQ_HOST_MAP_TREE: -		mutex_lock(&revmap_trees_mutex); -		radix_tree_delete(&host->revmap_data.tree, hwirq); -		mutex_unlock(&revmap_trees_mutex); -		break; -	} - -	/* Destroy map */ -	smp_mb(); -	irq_map[virq].hwirq = host->inval_irq; - -	irq_free_descs(virq, 1); -	/* Free it */ -	irq_free_virt(virq, 1); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_host *host, -			      irq_hw_number_t hwirq) -{ -	unsigned int i; -	unsigned int hint = hwirq % irq_virq_count; - -	/* Look for default host if nececssary */ -	if (host == NULL) -		host = irq_default_host; -	if (host == NULL) -		return NO_IRQ; - -	/* Slow path does a linear search of the map */ -	i = hint; -	do  { -		if (irq_map[i].host == host && -		    irq_map[i].hwirq == hwirq) -			return i; -		i++; -		if (i >= irq_virq_count) -			i = 4; -	} while (i != hint); -	return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); - -unsigned int irq_radix_revmap_lookup(struct irq_host *host, -				     irq_hw_number_t hwirq) -{ -	struct irq_map_entry *ptr; -	unsigned int virq; - -	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) -		return irq_find_mapping(host, hwirq); - -	/* -	 * The ptr returned references the static global irq_map. -	 * but freeing an irq can delete nodes along the path to -	 * do the lookup via call_rcu. -	 */ -	rcu_read_lock(); -	ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); -	rcu_read_unlock(); - -	/* -	 * If found in radix tree, then fine. -	 * Else fallback to linear lookup - this should not happen in practice -	 * as it means that we failed to insert the node in the radix tree. -	 */ -	if (ptr) -		virq = ptr - irq_map; -	else -		virq = irq_find_mapping(host, hwirq); - -	return virq; -} - -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, -			     irq_hw_number_t hwirq) -{ -	if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) -		return; - -	if (virq != NO_IRQ) { -		mutex_lock(&revmap_trees_mutex); -		radix_tree_insert(&host->revmap_data.tree, hwirq, -				  &irq_map[virq]); -		mutex_unlock(&revmap_trees_mutex); -	} -} - -unsigned int irq_linear_revmap(struct irq_host *host, -			       irq_hw_number_t hwirq) -{ -	unsigned int *revmap; - -	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) -		return irq_find_mapping(host, hwirq); - -	/* Check revmap bounds */ -	if (unlikely(hwirq >= host->revmap_data.linear.size)) -		return irq_find_mapping(host, hwirq); - -	/* Check if revmap was allocated */ -	revmap = host->revmap_data.linear.revmap; -	if (unlikely(revmap == NULL)) -		return irq_find_mapping(host, hwirq); - -	/* Fill up revmap with slow path if no mapping found */ -	if (unlikely(revmap[hwirq] == NO_IRQ)) -		revmap[hwirq] = irq_find_mapping(host, hwirq); - -	return revmap[hwirq]; -} - -unsigned int irq_alloc_virt(struct irq_host *host, -			    unsigned int count, -			    unsigned int hint) -{ -	unsigned long flags; -	unsigned int i, j, found = NO_IRQ; - -	if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS)) -		return NO_IRQ; - -	raw_spin_lock_irqsave(&irq_big_lock, flags); - -	/* Use hint for 1 interrupt if any */ -	if (count == 1 && hint >= NR_PRIORITY_IRQS && -	    hint < irq_virq_count && irq_map[hint].host == NULL) { -		found = hint; -		goto hint_found; -	} - -	/* Look for count consecutive numbers in the allocatable -	 * (non-legacy) space -	 */ -	for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) { -		if (irq_map[i].host != NULL) -			j = 0; -		else -			j++; - -		if (j == count) { -			found = i - count + 1; -			break; -		} -	} -	if (found == NO_IRQ) { -		raw_spin_unlock_irqrestore(&irq_big_lock, flags); -		return NO_IRQ; -	} - hint_found: -	for (i = found; i < (found + count); i++) { -		irq_map[i].hwirq = host->inval_irq; -		smp_wmb(); -		irq_map[i].host = host; -	} -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); -	return found; -} - -void irq_free_virt(unsigned int virq, unsigned int count) -{ -	unsigned long flags; -	unsigned int i; - -	WARN_ON(virq < NR_PRIORITY_IRQS); -	WARN_ON(count == 0 || (virq + count) > irq_virq_count); - -	if (virq < NR_PRIORITY_IRQS) { -		if (virq + count < NR_PRIORITY_IRQS) -			return; -		count  -= NR_PRIORITY_IRQS - virq; -		virq = NR_PRIORITY_IRQS; -	} - -	if (count > irq_virq_count || virq > irq_virq_count - count) { -		if (virq > irq_virq_count) -			return; -		count = irq_virq_count - virq; -	} - -	raw_spin_lock_irqsave(&irq_big_lock, flags); -	for (i = virq; i < (virq + count); i++) { -		struct irq_host *host; - -		host = irq_map[i].host; -		irq_map[i].hwirq = host->inval_irq; -		smp_wmb(); -		irq_map[i].host = NULL; -	} -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); -} - -#ifdef CONFIG_VIRQ_DEBUG -static int virq_debug_show(struct seq_file *m, void *private) -{ -	unsigned long flags; -	struct irq_desc *desc; -	const char *p; -	static const char none[] = "none"; -	void *data; -	int i; - -	seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq", -		      "chip name", "chip data", "host name"); - -	for (i = 1; i < nr_irqs; i++) { -		desc = irq_to_desc(i); -		if (!desc) -			continue; - -		raw_spin_lock_irqsave(&desc->lock, flags); - -		if (desc->action && desc->action->handler) { -			struct irq_chip *chip; - -			seq_printf(m, "%5d  ", i); -			seq_printf(m, "0x%05lx  ", irq_map[i].hwirq); - -			chip = irq_desc_get_chip(desc); -			if (chip && chip->name) -				p = chip->name; -			else -				p = none; -			seq_printf(m, "%-15s  ", p); - -			data = irq_desc_get_chip_data(desc); -			seq_printf(m, "0x%16p  ", data); - -			if (irq_map[i].host && irq_map[i].host->of_node) -				p = irq_map[i].host->of_node->full_name; -			else -				p = none; -			seq_printf(m, "%s\n", p); -		} - -		raw_spin_unlock_irqrestore(&desc->lock, flags); -	} - -	return 0; -} - -static int virq_debug_open(struct inode *inode, struct file *file) -{ -	return single_open(file, virq_debug_show, inode->i_private); -} - -static const struct file_operations virq_debug_fops = { -	.open = virq_debug_open, -	.read = seq_read, -	.llseek = seq_lseek, -	.release = single_release, -}; - -static int __init irq_debugfs_init(void) -{ -	if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, -				 NULL, &virq_debug_fops) == NULL) -		return -ENOMEM; - -	return 0; -} -device_initcall(irq_debugfs_init); -#endif /* CONFIG_VIRQ_DEBUG */ diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 7c37a947fb1..c1c4e2ae3f8 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -48,7 +48,7 @@ struct megamod_regs {  };  struct megamod_pic { -	struct irq_host	*irqhost; +	struct irq_domain *irqhost;  	struct megamod_regs __iomem *regs;  	raw_spinlock_t lock; @@ -116,7 +116,7 @@ static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)  	}  } -static int megamod_map(struct irq_host *h, unsigned int virq, +static int megamod_map(struct irq_domain *h, unsigned int virq,  		       irq_hw_number_t hw)  {  	struct megamod_pic *pic = h->host_data; @@ -136,21 +136,9 @@ static int megamod_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int megamod_xlate(struct irq_host *h, struct device_node *ct, -			 const u32 *intspec, unsigned int intsize, -			 irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ -	/* megamod intspecs must have 1 cell */ -	BUG_ON(intsize != 1); -	*out_hwirq = intspec[0]; -	*out_type = IRQ_TYPE_NONE; -	return 0; -} - -static struct irq_host_ops megamod_host_ops = { +static const struct irq_domain_ops megamod_domain_ops = {  	.map	= megamod_map, -	.xlate	= megamod_xlate, +	.xlate	= irq_domain_xlate_onecell,  };  static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output) @@ -223,9 +211,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np)  		return NULL;  	} -	pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -				      NR_COMBINERS * 32, &megamod_host_ops, -				      IRQ_UNMAPPED); +	pic->irqhost = irq_domain_add_linear(np, NR_COMBINERS * 32, +					     &megamod_domain_ops, pic);  	if (!pic->irqhost) {  		pr_err("%s: Could not alloc host.\n", np->full_name);  		goto error_free; diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index c8d6efb99db..11060fa87da 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -14,6 +14,7 @@ config MICROBLAZE  	select TRACING_SUPPORT  	select OF  	select OF_EARLY_FLATTREE +	select IRQ_DOMAIN  	select HAVE_GENERIC_HARDIRQS  	select GENERIC_IRQ_PROBE  	select GENERIC_IRQ_SHOW diff --git a/arch/microblaze/include/asm/hardirq.h b/arch/microblaze/include/asm/hardirq.h index cd1ac9aad56..fb3c05a0cbb 100644 --- a/arch/microblaze/include/asm/hardirq.h +++ b/arch/microblaze/include/asm/hardirq.h @@ -1,17 +1 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_HARDIRQ_H -#define _ASM_MICROBLAZE_HARDIRQ_H - -/* should be defined in each interrupt controller driver */ -extern unsigned int get_irq(struct pt_regs *regs); -  #include <asm-generic/hardirq.h> - -#endif /* _ASM_MICROBLAZE_HARDIRQ_H */ diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index a175132e449..bab3b1393ad 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h @@ -9,49 +9,13 @@  #ifndef _ASM_MICROBLAZE_IRQ_H  #define _ASM_MICROBLAZE_IRQ_H - -/* - * Linux IRQ# is currently offset by one to map to the hardware - * irq number. So hardware IRQ0 maps to Linux irq 1. - */ -#define NO_IRQ_OFFSET	1 -#define IRQ_OFFSET	NO_IRQ_OFFSET -#define NR_IRQS		(32 + IRQ_OFFSET) +#define NR_IRQS		(32 + 1)  #include <asm-generic/irq.h> -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -extern unsigned int nr_irq; -  struct pt_regs;  extern void do_IRQ(struct pt_regs *regs); -/** FIXME - not implement - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -	return; -} - -struct irq_host; - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, -					irq_hw_number_t hwirq); +/* should be defined in each interrupt controller driver */ +extern unsigned int get_irq(void);  #endif /* _ASM_MICROBLAZE_IRQ_H */ diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 44b177e2ab1..ad120672cee 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -9,6 +9,7 @@   */  #include <linux/init.h> +#include <linux/irqdomain.h>  #include <linux/irq.h>  #include <asm/page.h>  #include <linux/io.h> @@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;  #define INTC_BASE	intc_baseaddr  #endif -unsigned int nr_irq; -  /* No one else should require these constants, so define them locally here. */  #define ISR 0x00			/* Interrupt Status Register */  #define IPR 0x04			/* Interrupt Pending Register */ @@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {  	.irq_mask_ack = intc_mask_ack,  }; -unsigned int get_irq(struct pt_regs *regs) +static struct irq_domain *root_domain; + +unsigned int get_irq(void)  { -	int irq; +	unsigned int hwirq, irq = -1; -	/* -	 * NOTE: This function is the one that needs to be improved in -	 * order to handle multiple interrupt controllers. It currently -	 * is hardcoded to check for interrupts only on the first INTC. -	 */ -	irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET; -	pr_debug("get_irq: %d\n", irq); +	hwirq = in_be32(INTC_BASE + IVR); +	if (hwirq != -1U) +		irq = irq_find_mapping(root_domain, hwirq); + +	pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);  	return irq;  } +int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ +	u32 intr_mask = (u32)d->host_data; + +	if (intr_mask & (1 << hw)) { +		irq_set_chip_and_handler_name(irq, &intc_dev, +						handle_edge_irq, "edge"); +		irq_clear_status_flags(irq, IRQ_LEVEL); +	} else { +		irq_set_chip_and_handler_name(irq, &intc_dev, +						handle_level_irq, "level"); +		irq_set_status_flags(irq, IRQ_LEVEL); +	} +	return 0; +} + +static const struct irq_domain_ops xintc_irq_domain_ops = { +	.xlate = irq_domain_xlate_onetwocell, +	.map = xintc_map, +}; +  void __init init_IRQ(void)  { -	u32 i, intr_mask; +	u32 nr_irq, intr_mask;  	struct device_node *intc = NULL;  #ifdef CONFIG_SELFMOD_INTC  	unsigned int intc_baseaddr = 0; @@ -146,16 +166,9 @@ void __init init_IRQ(void)  	/* Turn on the Master Enable. */  	out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); -	for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) { -		if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) { -			irq_set_chip_and_handler_name(i, &intc_dev, -				handle_edge_irq, "edge"); -			irq_clear_status_flags(i, IRQ_LEVEL); -		} else { -			irq_set_chip_and_handler_name(i, &intc_dev, -				handle_level_irq, "level"); -			irq_set_status_flags(i, IRQ_LEVEL); -		} -		irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET; -	} +	/* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm +	 * lazy and Michal can clean it up to something nicer when he tests +	 * and commits this patch.  ~~gcl */ +	root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, +							(void *)intr_mask);  } diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index bbebcae72c0..ace700afbfd 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)  	trace_hardirqs_off();  	irq_enter(); -	irq = get_irq(regs); +	irq = get_irq();  next_irq:  	BUG_ON(!irq); -	/* Substract 1 because of get_irq */ -	generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET); +	generic_handle_irq(irq); -	irq = get_irq(regs); -	if (irq) { +	irq = get_irq(); +	if (irq != -1U) {  		pr_debug("next irq: %d\n", irq);  		++concurrent_irq;  		goto next_irq; @@ -48,18 +47,3 @@ next_irq:  	set_irq_regs(old_regs);  	trace_hardirqs_on();  } - -/* MS: There is no any advance mapping mechanism. We are using simple 32bit -  intc without any cascades or any connection that's why mapping is 1:1 */ -unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) -{ -	return hwirq + IRQ_OFFSET; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, -				   const u32 *intspec, unsigned int intsize) -{ -	return intspec[0] + IRQ_OFFSET; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 604cd9dd133..70e6d0b41ab 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p)  	unflatten_device_tree(); -	/* NOTE I think that this function is not necessary to call */ -	/* irq_early_init(); */  	setup_cpuinfo();  	microblaze_cache_init(); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5ab6e89603c..edbbae17e82 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2327,6 +2327,7 @@ config USE_OF  	bool "Flattened Device Tree support"  	select OF  	select OF_EARLY_FLATTREE +	select IRQ_DOMAIN  	help  	  Include support for flattened device tree machine descriptions. diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 2354c870a63..fb698dc09bc 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -11,15 +11,12 @@  #include <linux/linkage.h>  #include <linux/smp.h> +#include <linux/irqdomain.h>  #include <asm/mipsmtregs.h>  #include <irq.h> -static inline void irq_dispose_mapping(unsigned int virq) -{ -} -  #ifdef CONFIG_I8259  static inline int irq_canonicalize(int irq)  { diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 6b8b4208481..558b5395795 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,  }  #endif -/* - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# - * - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are - * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not - * supported. - */ -unsigned int irq_create_of_mapping(struct device_node *controller, -				   const u32 *intspec, unsigned int intsize) -{ -	return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); -  void __init early_init_devtree(void *params)  {  	/* Setup flat device-tree pointer */ diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h index e1f3fe26606..bbb34e5343a 100644 --- a/arch/openrisc/include/asm/prom.h +++ b/arch/openrisc/include/asm/prom.h @@ -24,6 +24,7 @@  #include <linux/types.h>  #include <asm/irq.h> +#include <linux/irqdomain.h>  #include <linux/atomic.h>  #include <linux/of_irq.h>  #include <linux/of_fdt.h> @@ -63,15 +64,6 @@ extern const void *of_get_mac_address(struct device_node *np);  struct pci_dev;  extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -/* This routine is here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes.  We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} -  #endif /* __ASSEMBLY__ */  #endif /* __KERNEL__ */  #endif /* _ASM_OPENRISC_PROM_H */ diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1919634a9b3..303703d716f 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -135,6 +135,7 @@ config PPC  	select HAVE_GENERIC_HARDIRQS  	select HAVE_SPARSE_IRQ  	select IRQ_PER_CPU +	select IRQ_DOMAIN  	select GENERIC_IRQ_SHOW  	select GENERIC_IRQ_SHOW_LEVEL  	select IRQ_FORCED_THREADING diff --git a/arch/powerpc/include/asm/ehv_pic.h b/arch/powerpc/include/asm/ehv_pic.h index a9e1f4f796f..dc7d48e3ea9 100644 --- a/arch/powerpc/include/asm/ehv_pic.h +++ b/arch/powerpc/include/asm/ehv_pic.h @@ -25,7 +25,7 @@  struct ehv_pic {  	/* The remapper for this EHV_PIC */ -	struct irq_host	*irqhost; +	struct irq_domain	*irqhost;  	/* The "linux" controller struct */  	struct irq_chip	hc_irq; diff --git a/arch/powerpc/include/asm/i8259.h b/arch/powerpc/include/asm/i8259.h index 105ade297aa..c3fdfbd5a67 100644 --- a/arch/powerpc/include/asm/i8259.h +++ b/arch/powerpc/include/asm/i8259.h @@ -6,7 +6,7 @@  extern void i8259_init(struct device_node *node, unsigned long intack_addr);  extern unsigned int i8259_irq(void); -extern struct irq_host *i8259_get_host(void); +extern struct irq_domain *i8259_get_host(void);  #endif /* __KERNEL__ */  #endif /* _ASM_POWERPC_I8259_H */ diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index c0e1bc319e3..fe0b09dceb7 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -9,6 +9,7 @@   * 2 of the License, or (at your option) any later version.   */ +#include <linux/irqdomain.h>  #include <linux/threads.h>  #include <linux/list.h>  #include <linux/radix-tree.h> @@ -35,258 +36,12 @@ extern atomic_t ppc_n_lost_interrupts;  /* Total number of virq in the platform */  #define NR_IRQS		CONFIG_NR_IRQS -/* Number of irqs reserved for the legacy controller */ -#define NUM_ISA_INTERRUPTS	16 -  /* Same thing, used by the generic IRQ code */  #define NR_IRQS_LEGACY		NUM_ISA_INTERRUPTS -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -/* Interrupt controller "host" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The host - * structure is generally created by the PIC code for a given PIC instance - * (though a host can cover more than one PIC if they have a flat number - * model). It's the host callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures are fairly agnostic to the fact that - * we use an open firmware device-tree. We do have references to struct - * device_node in two places: in irq_find_host() to find the host matching - * a given interrupt controller node, and of course as an argument to its - * counterpart host->ops->match() callback. However, those are treated as - * generic pointers by the core and the fact that it's actually a device-node - * pointer is purely a convention between callers and implementation. This - * code could thus be used on other architectures by replacing those two - * by some sort of arch-specific void * "token" used to identify interrupt - * controllers. - */ -struct irq_host; -struct radix_tree_root; - -/* Functions below are provided by the host and called whenever a new mapping - * is created or an old mapping is disposed. The host can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_host_ops { -	/* Match an interrupt controller device node to a host, returns -	 * 1 on a match -	 */ -	int (*match)(struct irq_host *h, struct device_node *node); - -	/* Create or update a mapping between a virtual irq number and a hw -	 * irq number. This is called only once for a given mapping. -	 */ -	int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - -	/* Dispose of such a mapping */ -	void (*unmap)(struct irq_host *h, unsigned int virq); - -	/* Translate device-tree interrupt specifier from raw format coming -	 * from the firmware to a irq_hw_number_t (interrupt line number) and -	 * type (sense) that can be passed to set_irq_type(). In the absence -	 * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() -	 * will return the hw number in the first cell and IRQ_TYPE_NONE for -	 * the type (which amount to keeping whatever default value the -	 * interrupt controller has for that line) -	 */ -	int (*xlate)(struct irq_host *h, struct device_node *ctrler, -		     const u32 *intspec, unsigned int intsize, -		     irq_hw_number_t *out_hwirq, unsigned int *out_type); -}; - -struct irq_host { -	struct list_head	link; - -	/* type of reverse mapping technique */ -	unsigned int		revmap_type; -#define IRQ_HOST_MAP_LEGACY     0 /* legacy 8259, gets irqs 1..15 */ -#define IRQ_HOST_MAP_NOMAP	1 /* no fast reverse mapping */ -#define IRQ_HOST_MAP_LINEAR	2 /* linear map of interrupts */ -#define IRQ_HOST_MAP_TREE	3 /* radix tree */ -	union { -		struct { -			unsigned int size; -			unsigned int *revmap; -		} linear; -		struct radix_tree_root tree; -	} revmap_data; -	struct irq_host_ops	*ops; -	void			*host_data; -	irq_hw_number_t		inval_irq; - -	/* Optional device node pointer */ -	struct device_node	*of_node; -}; -  struct irq_data;  extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);  extern irq_hw_number_t virq_to_hw(unsigned int virq); -extern bool virq_is_host(unsigned int virq, struct irq_host *host); - -/** - * irq_alloc_host - Allocate a new irq_host data structure - * @of_node: optional device-tree node of the interrupt controller - * @revmap_type: type of reverse mapping to use - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map - * @ops: map/unmap host callbacks - * @inval_irq: provide a hw number in that host space that is always invalid - * - * Allocates and initialize and irq_host structure. Note that in the case of - * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns - * for all legacy interrupts except 0 (which is always the invalid irq for - * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated - * later during boot automatically (the reverse mapping will use the slow path - * until that happens). - */ -extern struct irq_host *irq_alloc_host(struct device_node *of_node, -				       unsigned int revmap_type, -				       unsigned int revmap_arg, -				       struct irq_host_ops *ops, -				       irq_hw_number_t inval_irq); - - -/** - * irq_find_host - Locates a host for a given device node - * @node: device-tree node of the interrupt controller - */ -extern struct irq_host *irq_find_host(struct device_node *node); - - -/** - * irq_set_default_host - Set a "default" host - * @host: default host pointer - * - * For convenience, it's possible to set a "default" host that will be used - * whenever NULL is passed to irq_create_mapping(). It makes life easier for - * platforms that want to manipulate a few hard coded interrupt numbers that - * aren't properly represented in the device-tree. - */ -extern void irq_set_default_host(struct irq_host *host); - - -/** - * irq_set_virq_count - Set the maximum number of virt irqs - * @count: number of linux virtual irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -extern void irq_set_virq_count(unsigned int count); - - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, -				       irq_hw_number_t hwirq); - - -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_find_mapping - Find a linux virq from an hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a slow path, for use by generic code. It's expected that an - * irq controller implementation directly calls the appropriate low level - * mapping function. - */ -extern unsigned int irq_find_mapping(struct irq_host *host, -				     irq_hw_number_t hwirq); - -/** - * irq_create_direct_mapping - Allocate a virq for direct mapping - * @host: host to allocate the virq for or NULL for default host - * - * This routine is used for irq controllers which can choose the hardware - * interrupt numbers they generate. In such a case it's simplest to use - * the linux virq as the hardware interrupt number. - */ -extern unsigned int irq_create_direct_mapping(struct irq_host *host); - -/** - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. - * @host: host owning this hardware interrupt - * @virq: linux irq number - * @hwirq: hardware irq number in that host space - * - * This is for use by irq controllers that use a radix tree reverse - * mapping for fast lookup. - */ -extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, -				    irq_hw_number_t hwirq); - -/** - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses radix tree - * revmaps - */ -extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, -					    irq_hw_number_t hwirq); - -/** - * irq_linear_revmap - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses linear - * revmaps. It does fallback to the slow path if the revmap doesn't exist - * yet and will create the revmap entry with appropriate locking - */ - -extern unsigned int irq_linear_revmap(struct irq_host *host, -				      irq_hw_number_t hwirq); - - - -/** - * irq_alloc_virt - Allocate virtual irq numbers - * @host: host owning these new virtual irqs - * @count: number of consecutive numbers to allocate - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping - * - * This is a low level function that is used internally by irq_create_mapping() - * and that can be used by some irq controllers implementations for things - * like allocating ranges of numbers for MSIs. The revmaps are left untouched. - */ -extern unsigned int irq_alloc_virt(struct irq_host *host, -				   unsigned int count, -				   unsigned int hint); - -/** - * irq_free_virt - Free virtual irq numbers - * @virq: virtual irq number of the first interrupt to free - * @count: number of interrupts to free - * - * This function is the opposite of irq_alloc_virt. It will not clear reverse - * maps, this should be done previously by unmap'ing the interrupt. In fact, - * all interrupts covered by the range being freed should have been unmapped - * prior to calling this. - */ -extern void irq_free_virt(unsigned int virq, unsigned int count);  /**   * irq_early_init - Init irq remapping subsystem diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 67b4d983723..a5b7c56237f 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -255,7 +255,7 @@ struct mpic  	struct device_node *node;  	/* The remapper for this MPIC */ -	struct irq_host		*irqhost; +	struct irq_domain	*irqhost;  	/* The "linux" controller struct */  	struct irq_chip		hc_irq; diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index c48de98ba94..4ae9a09c3b8 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -86,7 +86,7 @@ struct ics {  extern unsigned int xics_default_server;  extern unsigned int xics_default_distrib_server;  extern unsigned int xics_interrupt_server_size; -extern struct irq_host *xics_host; +extern struct irq_domain *xics_host;  struct xics_cppr {  	unsigned char stack[MAX_NUM_PRIORITIES]; diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 01e2877e8e0..bdfb3eee3e6 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -490,409 +490,19 @@ void do_softirq(void)  	local_irq_restore(flags);  } - -/* - * IRQ controller and virtual interrupts - */ - -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { -	irq_hw_number_t	hwirq; -	struct irq_host	*host; -}; - -static LIST_HEAD(irq_hosts); -static DEFINE_RAW_SPINLOCK(irq_big_lock); -static DEFINE_MUTEX(revmap_trees_mutex); -static struct irq_map_entry irq_map[NR_IRQS]; -static unsigned int irq_virq_count = NR_IRQS; -static struct irq_host *irq_default_host; -  irq_hw_number_t irqd_to_hwirq(struct irq_data *d)  { -	return irq_map[d->irq].hwirq; +	return d->hwirq;  }  EXPORT_SYMBOL_GPL(irqd_to_hwirq);  irq_hw_number_t virq_to_hw(unsigned int virq)  { -	return irq_map[virq].hwirq; +	struct irq_data *irq_data = irq_get_irq_data(virq); +	return WARN_ON(!irq_data) ? 0 : irq_data->hwirq;  }  EXPORT_SYMBOL_GPL(virq_to_hw); -bool virq_is_host(unsigned int virq, struct irq_host *host) -{ -	return irq_map[virq].host == host; -} -EXPORT_SYMBOL_GPL(virq_is_host); - -static int default_irq_host_match(struct irq_host *h, struct device_node *np) -{ -	return h->of_node != NULL && h->of_node == np; -} - -struct irq_host *irq_alloc_host(struct device_node *of_node, -				unsigned int revmap_type, -				unsigned int revmap_arg, -				struct irq_host_ops *ops, -				irq_hw_number_t inval_irq) -{ -	struct irq_host *host; -	unsigned int size = sizeof(struct irq_host); -	unsigned int i; -	unsigned int *rmap; -	unsigned long flags; - -	/* Allocate structure and revmap table if using linear mapping */ -	if (revmap_type == IRQ_HOST_MAP_LINEAR) -		size += revmap_arg * sizeof(unsigned int); -	host = kzalloc(size, GFP_KERNEL); -	if (host == NULL) -		return NULL; - -	/* Fill structure */ -	host->revmap_type = revmap_type; -	host->inval_irq = inval_irq; -	host->ops = ops; -	host->of_node = of_node_get(of_node); - -	if (host->ops->match == NULL) -		host->ops->match = default_irq_host_match; - -	raw_spin_lock_irqsave(&irq_big_lock, flags); - -	/* If it's a legacy controller, check for duplicates and -	 * mark it as allocated (we use irq 0 host pointer for that -	 */ -	if (revmap_type == IRQ_HOST_MAP_LEGACY) { -		if (irq_map[0].host != NULL) { -			raw_spin_unlock_irqrestore(&irq_big_lock, flags); -			of_node_put(host->of_node); -			kfree(host); -			return NULL; -		} -		irq_map[0].host = host; -	} - -	list_add(&host->link, &irq_hosts); -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); - -	/* Additional setups per revmap type */ -	switch(revmap_type) { -	case IRQ_HOST_MAP_LEGACY: -		/* 0 is always the invalid number for legacy */ -		host->inval_irq = 0; -		/* setup us as the host for all legacy interrupts */ -		for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { -			irq_map[i].hwirq = i; -			smp_wmb(); -			irq_map[i].host = host; -			smp_wmb(); - -			/* Legacy flags are left to default at this point, -			 * one can then use irq_create_mapping() to -			 * explicitly change them -			 */ -			ops->map(host, i, i); - -			/* Clear norequest flags */ -			irq_clear_status_flags(i, IRQ_NOREQUEST); -		} -		break; -	case IRQ_HOST_MAP_LINEAR: -		rmap = (unsigned int *)(host + 1); -		for (i = 0; i < revmap_arg; i++) -			rmap[i] = NO_IRQ; -		host->revmap_data.linear.size = revmap_arg; -		smp_wmb(); -		host->revmap_data.linear.revmap = rmap; -		break; -	case IRQ_HOST_MAP_TREE: -		INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); -		break; -	default: -		break; -	} - -	pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); - -	return host; -} - -struct irq_host *irq_find_host(struct device_node *node) -{ -	struct irq_host *h, *found = NULL; -	unsigned long flags; - -	/* We might want to match the legacy controller last since -	 * it might potentially be set to match all interrupts in -	 * the absence of a device node. This isn't a problem so far -	 * yet though... -	 */ -	raw_spin_lock_irqsave(&irq_big_lock, flags); -	list_for_each_entry(h, &irq_hosts, link) -		if (h->ops->match(h, node)) { -			found = h; -			break; -		} -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); -	return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_host *host) -{ -	pr_debug("irq: Default host set to @0x%p\n", host); - -	irq_default_host = host; -} - -void irq_set_virq_count(unsigned int count) -{ -	pr_debug("irq: Trying to set virq count to %d\n", count); - -	BUG_ON(count < NUM_ISA_INTERRUPTS); -	if (count < NR_IRQS) -		irq_virq_count = count; -} - -static int irq_setup_virq(struct irq_host *host, unsigned int virq, -			    irq_hw_number_t hwirq) -{ -	int res; - -	res = irq_alloc_desc_at(virq, 0); -	if (res != virq) { -		pr_debug("irq: -> allocating desc failed\n"); -		goto error; -	} - -	/* map it */ -	smp_wmb(); -	irq_map[virq].hwirq = hwirq; -	smp_mb(); - -	if (host->ops->map(host, virq, hwirq)) { -		pr_debug("irq: -> mapping failed, freeing\n"); -		goto errdesc; -	} - -	irq_clear_status_flags(virq, IRQ_NOREQUEST); - -	return 0; - -errdesc: -	irq_free_descs(virq, 1); -error: -	irq_free_virt(virq, 1); -	return -1; -} - -unsigned int irq_create_direct_mapping(struct irq_host *host) -{ -	unsigned int virq; - -	if (host == NULL) -		host = irq_default_host; - -	BUG_ON(host == NULL); -	WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); - -	virq = irq_alloc_virt(host, 1, 0); -	if (virq == NO_IRQ) { -		pr_debug("irq: create_direct virq allocation failed\n"); -		return NO_IRQ; -	} - -	pr_debug("irq: create_direct obtained virq %d\n", virq); - -	if (irq_setup_virq(host, virq, virq)) -		return NO_IRQ; - -	return virq; -} - -unsigned int irq_create_mapping(struct irq_host *host, -				irq_hw_number_t hwirq) -{ -	unsigned int virq, hint; - -	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); - -	/* Look for default host if nececssary */ -	if (host == NULL) -		host = irq_default_host; -	if (host == NULL) { -		printk(KERN_WARNING "irq_create_mapping called for" -		       " NULL host, hwirq=%lx\n", hwirq); -		WARN_ON(1); -		return NO_IRQ; -	} -	pr_debug("irq: -> using host @%p\n", host); - -	/* Check if mapping already exists */ -	virq = irq_find_mapping(host, hwirq); -	if (virq != NO_IRQ) { -		pr_debug("irq: -> existing mapping on virq %d\n", virq); -		return virq; -	} - -	/* Get a virtual interrupt number */ -	if (host->revmap_type == IRQ_HOST_MAP_LEGACY) { -		/* Handle legacy */ -		virq = (unsigned int)hwirq; -		if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) -			return NO_IRQ; -		return virq; -	} else { -		/* Allocate a virtual interrupt number */ -		hint = hwirq % irq_virq_count; -		virq = irq_alloc_virt(host, 1, hint); -		if (virq == NO_IRQ) { -			pr_debug("irq: -> virq allocation failed\n"); -			return NO_IRQ; -		} -	} - -	if (irq_setup_virq(host, virq, hwirq)) -		return NO_IRQ; - -	pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", -		hwirq, host->of_node ? host->of_node->full_name : "null", virq); - -	return virq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, -				   const u32 *intspec, unsigned int intsize) -{ -	struct irq_host *host; -	irq_hw_number_t hwirq; -	unsigned int type = IRQ_TYPE_NONE; -	unsigned int virq; - -	if (controller == NULL) -		host = irq_default_host; -	else -		host = irq_find_host(controller); -	if (host == NULL) { -		printk(KERN_WARNING "irq: no irq host found for %s !\n", -		       controller->full_name); -		return NO_IRQ; -	} - -	/* If host has no translation, then we assume interrupt line */ -	if (host->ops->xlate == NULL) -		hwirq = intspec[0]; -	else { -		if (host->ops->xlate(host, controller, intspec, intsize, -				     &hwirq, &type)) -			return NO_IRQ; -	} - -	/* Create mapping */ -	virq = irq_create_mapping(host, hwirq); -	if (virq == NO_IRQ) -		return virq; - -	/* Set type if specified and different than the current one */ -	if (type != IRQ_TYPE_NONE && -	    type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) -		irq_set_irq_type(virq, type); -	return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - -void irq_dispose_mapping(unsigned int virq) -{ -	struct irq_host *host; -	irq_hw_number_t hwirq; - -	if (virq == NO_IRQ) -		return; - -	host = irq_map[virq].host; -	if (WARN_ON(host == NULL)) -		return; - -	/* Never unmap legacy interrupts */ -	if (host->revmap_type == IRQ_HOST_MAP_LEGACY) -		return; - -	irq_set_status_flags(virq, IRQ_NOREQUEST); - -	/* remove chip and handler */ -	irq_set_chip_and_handler(virq, NULL, NULL); - -	/* Make sure it's completed */ -	synchronize_irq(virq); - -	/* Tell the PIC about it */ -	if (host->ops->unmap) -		host->ops->unmap(host, virq); -	smp_mb(); - -	/* Clear reverse map */ -	hwirq = irq_map[virq].hwirq; -	switch(host->revmap_type) { -	case IRQ_HOST_MAP_LINEAR: -		if (hwirq < host->revmap_data.linear.size) -			host->revmap_data.linear.revmap[hwirq] = NO_IRQ; -		break; -	case IRQ_HOST_MAP_TREE: -		mutex_lock(&revmap_trees_mutex); -		radix_tree_delete(&host->revmap_data.tree, hwirq); -		mutex_unlock(&revmap_trees_mutex); -		break; -	} - -	/* Destroy map */ -	smp_mb(); -	irq_map[virq].hwirq = host->inval_irq; - -	irq_free_descs(virq, 1); -	/* Free it */ -	irq_free_virt(virq, 1); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_host *host, -			      irq_hw_number_t hwirq) -{ -	unsigned int i; -	unsigned int hint = hwirq % irq_virq_count; - -	/* Look for default host if nececssary */ -	if (host == NULL) -		host = irq_default_host; -	if (host == NULL) -		return NO_IRQ; - -	/* legacy -> bail early */ -	if (host->revmap_type == IRQ_HOST_MAP_LEGACY) -		return hwirq; - -	/* Slow path does a linear search of the map */ -	if (hint < NUM_ISA_INTERRUPTS) -		hint = NUM_ISA_INTERRUPTS; -	i = hint; -	do  { -		if (irq_map[i].host == host && -		    irq_map[i].hwirq == hwirq) -			return i; -		i++; -		if (i >= irq_virq_count) -			i = NUM_ISA_INTERRUPTS; -	} while(i != hint); -	return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); -  #ifdef CONFIG_SMP  int irq_choose_cpu(const struct cpumask *mask)  { @@ -929,232 +539,11 @@ int irq_choose_cpu(const struct cpumask *mask)  }  #endif -unsigned int irq_radix_revmap_lookup(struct irq_host *host, -				     irq_hw_number_t hwirq) -{ -	struct irq_map_entry *ptr; -	unsigned int virq; - -	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) -		return irq_find_mapping(host, hwirq); - -	/* -	 * The ptr returned references the static global irq_map. -	 * but freeing an irq can delete nodes along the path to -	 * do the lookup via call_rcu. -	 */ -	rcu_read_lock(); -	ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); -	rcu_read_unlock(); - -	/* -	 * If found in radix tree, then fine. -	 * Else fallback to linear lookup - this should not happen in practice -	 * as it means that we failed to insert the node in the radix tree. -	 */ -	if (ptr) -		virq = ptr - irq_map; -	else -		virq = irq_find_mapping(host, hwirq); - -	return virq; -} - -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, -			     irq_hw_number_t hwirq) -{ -	if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) -		return; - -	if (virq != NO_IRQ) { -		mutex_lock(&revmap_trees_mutex); -		radix_tree_insert(&host->revmap_data.tree, hwirq, -				  &irq_map[virq]); -		mutex_unlock(&revmap_trees_mutex); -	} -} - -unsigned int irq_linear_revmap(struct irq_host *host, -			       irq_hw_number_t hwirq) -{ -	unsigned int *revmap; - -	if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) -		return irq_find_mapping(host, hwirq); - -	/* Check revmap bounds */ -	if (unlikely(hwirq >= host->revmap_data.linear.size)) -		return irq_find_mapping(host, hwirq); - -	/* Check if revmap was allocated */ -	revmap = host->revmap_data.linear.revmap; -	if (unlikely(revmap == NULL)) -		return irq_find_mapping(host, hwirq); - -	/* Fill up revmap with slow path if no mapping found */ -	if (unlikely(revmap[hwirq] == NO_IRQ)) -		revmap[hwirq] = irq_find_mapping(host, hwirq); - -	return revmap[hwirq]; -} - -unsigned int irq_alloc_virt(struct irq_host *host, -			    unsigned int count, -			    unsigned int hint) -{ -	unsigned long flags; -	unsigned int i, j, found = NO_IRQ; - -	if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS)) -		return NO_IRQ; - -	raw_spin_lock_irqsave(&irq_big_lock, flags); - -	/* Use hint for 1 interrupt if any */ -	if (count == 1 && hint >= NUM_ISA_INTERRUPTS && -	    hint < irq_virq_count && irq_map[hint].host == NULL) { -		found = hint; -		goto hint_found; -	} - -	/* Look for count consecutive numbers in the allocatable -	 * (non-legacy) space -	 */ -	for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) { -		if (irq_map[i].host != NULL) -			j = 0; -		else -			j++; - -		if (j == count) { -			found = i - count + 1; -			break; -		} -	} -	if (found == NO_IRQ) { -		raw_spin_unlock_irqrestore(&irq_big_lock, flags); -		return NO_IRQ; -	} - hint_found: -	for (i = found; i < (found + count); i++) { -		irq_map[i].hwirq = host->inval_irq; -		smp_wmb(); -		irq_map[i].host = host; -	} -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); -	return found; -} - -void irq_free_virt(unsigned int virq, unsigned int count) -{ -	unsigned long flags; -	unsigned int i; - -	WARN_ON (virq < NUM_ISA_INTERRUPTS); -	WARN_ON (count == 0 || (virq + count) > irq_virq_count); - -	if (virq < NUM_ISA_INTERRUPTS) { -		if (virq + count < NUM_ISA_INTERRUPTS) -			return; -		count  =- NUM_ISA_INTERRUPTS - virq; -		virq = NUM_ISA_INTERRUPTS; -	} - -	if (count > irq_virq_count || virq > irq_virq_count - count) { -		if (virq > irq_virq_count) -			return; -		count = irq_virq_count - virq; -	} - -	raw_spin_lock_irqsave(&irq_big_lock, flags); -	for (i = virq; i < (virq + count); i++) { -		struct irq_host *host; - -		host = irq_map[i].host; -		irq_map[i].hwirq = host->inval_irq; -		smp_wmb(); -		irq_map[i].host = NULL; -	} -	raw_spin_unlock_irqrestore(&irq_big_lock, flags); -} -  int arch_early_irq_init(void)  {  	return 0;  } -#ifdef CONFIG_VIRQ_DEBUG -static int virq_debug_show(struct seq_file *m, void *private) -{ -	unsigned long flags; -	struct irq_desc *desc; -	const char *p; -	static const char none[] = "none"; -	void *data; -	int i; - -	seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq", -		      "chip name", "chip data", "host name"); - -	for (i = 1; i < nr_irqs; i++) { -		desc = irq_to_desc(i); -		if (!desc) -			continue; - -		raw_spin_lock_irqsave(&desc->lock, flags); - -		if (desc->action && desc->action->handler) { -			struct irq_chip *chip; - -			seq_printf(m, "%5d  ", i); -			seq_printf(m, "0x%05lx  ", irq_map[i].hwirq); - -			chip = irq_desc_get_chip(desc); -			if (chip && chip->name) -				p = chip->name; -			else -				p = none; -			seq_printf(m, "%-15s  ", p); - -			data = irq_desc_get_chip_data(desc); -			seq_printf(m, "0x%16p  ", data); - -			if (irq_map[i].host && irq_map[i].host->of_node) -				p = irq_map[i].host->of_node->full_name; -			else -				p = none; -			seq_printf(m, "%s\n", p); -		} - -		raw_spin_unlock_irqrestore(&desc->lock, flags); -	} - -	return 0; -} - -static int virq_debug_open(struct inode *inode, struct file *file) -{ -	return single_open(file, virq_debug_show, inode->i_private); -} - -static const struct file_operations virq_debug_fops = { -	.open = virq_debug_open, -	.read = seq_read, -	.llseek = seq_lseek, -	.release = single_release, -}; - -static int __init irq_debugfs_init(void) -{ -	if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, -				 NULL, &virq_debug_fops) == NULL) -		return -ENOMEM; - -	return 0; -} -__initcall(irq_debugfs_init); -#endif /* CONFIG_VIRQ_DEBUG */ -  #ifdef CONFIG_PPC64  static int __init setup_noirqdistrib(char *str)  { diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 9f09319352c..ca3a062ed1b 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -21,7 +21,7 @@  #include <asm/prom.h>  static struct device_node *cpld_pic_node; -static struct irq_host *cpld_pic_host; +static struct irq_domain *cpld_pic_host;  /*   * Bits to ignore in the misc_status register @@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)  }  static int -cpld_pic_host_match(struct irq_host *h, struct device_node *node) +cpld_pic_host_match(struct irq_domain *h, struct device_node *node)  {  	return cpld_pic_node == node;  }  static int -cpld_pic_host_map(struct irq_host *h, unsigned int virq, +cpld_pic_host_map(struct irq_domain *h, unsigned int virq,  			     irq_hw_number_t hw)  {  	irq_set_status_flags(virq, IRQ_LEVEL); @@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct -irq_host_ops cpld_pic_host_ops = { +static const struct irq_domain_ops cpld_pic_host_ops = {  	.match = cpld_pic_host_match,  	.map = cpld_pic_host_map,  }; @@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void)  	cpld_pic_node = of_node_get(np); -	cpld_pic_host = -	    irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); +	cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);  	if (!cpld_pic_host) {  		printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");  		goto end; diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 96f85e5e0cd..17d91b7da31 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = {  struct media5200_irq {  	void __iomem *regs;  	spinlock_t lock; -	struct irq_host *irqhost; +	struct irq_domain *irqhost;  };  struct media5200_irq media5200_irq; @@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)  	raw_spin_unlock(&desc->lock);  } -static int media5200_irq_map(struct irq_host *h, unsigned int virq, +static int media5200_irq_map(struct irq_domain *h, unsigned int virq,  			     irq_hw_number_t hw)  {  	pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw); @@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, +static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops media5200_irq_ops = { +static const struct irq_domain_ops media5200_irq_ops = {  	.map = media5200_irq_map,  	.xlate = media5200_irq_xlate,  }; @@ -173,15 +173,12 @@ static void __init media5200_init_irq(void)  	spin_lock_init(&media5200_irq.lock); -	media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR, -					       MEDIA5200_NUM_IRQS, -					       &media5200_irq_ops, -1); +	media5200_irq.irqhost = irq_domain_add_linear(fpga_np, +			MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);  	if (!media5200_irq.irqhost)  		goto out;  	pr_debug("%s: allocated irqhost\n", __func__); -	media5200_irq.irqhost->host_data = &media5200_irq; -  	irq_set_handler_data(cascade_virq, &media5200_irq);  	irq_set_chained_handler(cascade_virq, media5200_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index f94f06e5276..028470b9588 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");   * @regs: virtual address of GPT registers   * @lock: spinlock to coordinate between different functions.   * @gc: gpio_chip instance structure; used when GPIO is enabled - * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported + * @irqhost: Pointer to irq_domain instance; used when IRQ mode is supported   * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates   *   if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates   *   if the timer is actively used as wdt which blocks gpt functions @@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv {  	struct device *dev;  	struct mpc52xx_gpt __iomem *regs;  	spinlock_t lock; -	struct irq_host *irqhost; +	struct irq_domain *irqhost;  	u32 ipb_freq;  	u8 wdt_mode; @@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)  	}  } -static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_gpt_irq_map(struct irq_domain *h, unsigned int virq,  			       irq_hw_number_t hw)  {  	struct mpc52xx_gpt_priv *gpt = h->host_data; @@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops mpc52xx_gpt_irq_ops = { +static const struct irq_domain_ops mpc52xx_gpt_irq_ops = {  	.map = mpc52xx_gpt_irq_map,  	.xlate = mpc52xx_gpt_irq_xlate,  }; @@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)  	if (!cascade_virq)  		return; -	gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, -				      &mpc52xx_gpt_irq_ops, -1); +	gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt);  	if (!gpt->irqhost) { -		dev_err(gpt->dev, "irq_alloc_host() failed\n"); +		dev_err(gpt->dev, "irq_domain_add_linear() failed\n");  		return;  	} -	gpt->irqhost->host_data = gpt;  	irq_set_handler_data(cascade_virq, gpt);  	irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1a9a4957057..8520b58a5e9 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = {  static struct mpc52xx_intr __iomem *intr;  static struct mpc52xx_sdma __iomem *sdma; -static struct irq_host *mpc52xx_irqhost = NULL; +static struct irq_domain *mpc52xx_irqhost = NULL;  static unsigned char mpc52xx_map_senses[4] = {  	IRQ_TYPE_LEVEL_HIGH, @@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2)  /**   * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property   */ -static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,  /**   * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure   */ -static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,  			       irq_hw_number_t irq)  {  	int l1irq; @@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops mpc52xx_irqhost_ops = { +static const struct irq_domain_ops mpc52xx_irqhost_ops = {  	.xlate = mpc52xx_irqhost_xlate,  	.map = mpc52xx_irqhost_map,  }; @@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void)  	 * As last step, add an irq host to translate the real  	 * hw irq information provided by the ofw to linux virq  	 */ -	mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, +	mpc52xx_irqhost = irq_domain_add_linear(picnode,  	                                 MPC52xx_IRQ_HIGHTESTHWIRQ, -	                                 &mpc52xx_irqhost_ops, -1); +	                                 &mpc52xx_irqhost_ops, NULL);  	if (!mpc52xx_irqhost)  		panic(__FILE__ ": Cannot allocate the IRQ host\n"); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 8ccf9ed62fe..328d221fd1c 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock);  struct pq2ads_pci_pic {  	struct device_node *node; -	struct irq_host *host; +	struct irq_domain *host;  	struct {  		u32 stat; @@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)  	}  } -static int pci_pic_host_map(struct irq_host *h, unsigned int virq, +static int pci_pic_host_map(struct irq_domain *h, unsigned int virq,  			    irq_hw_number_t hw)  {  	irq_set_status_flags(virq, IRQ_LEVEL); @@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops pci_pic_host_ops = { +static const struct irq_domain_ops pci_pic_host_ops = {  	.map = pci_pic_host_map,  };  int __init pq2ads_pci_init_irq(void)  {  	struct pq2ads_pci_pic *priv; -	struct irq_host *host; +	struct irq_domain *host;  	struct device_node *np;  	int ret = -ENODEV;  	int irq; @@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void)  	out_be32(&priv->regs->mask, ~0);  	mb(); -	host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, -	                      &pci_pic_host_ops, NUM_IRQS); +	host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);  	if (!host) {  		ret = -ENOMEM;  		goto out_unmap_regs;  	} -	host->host_data = priv; -  	priv->host = host; -	host->host_data = priv;  	irq_set_handler_data(irq, priv);  	irq_set_chained_handler(irq, pq2ads_pci_irq_demux); diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 12cb9bb2cc6..3bbbf748948 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {  static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);  static void __iomem *socrates_fpga_pic_iobase; -static struct irq_host *socrates_fpga_pic_irq_host; +static struct irq_domain *socrates_fpga_pic_irq_host;  static unsigned int socrates_fpga_irqs[3];  static inline uint32_t socrates_fpga_pic_read(int reg) @@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = {  	.irq_set_type	= socrates_fpga_pic_set_type,  }; -static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, +static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,  		irq_hw_number_t hwirq)  {  	/* All interrupts are LEVEL sensitive */ @@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int socrates_fpga_pic_host_xlate(struct irq_host *h, +static int socrates_fpga_pic_host_xlate(struct irq_domain *h,  		struct device_node *ct,	const u32 *intspec, unsigned int intsize,  		irq_hw_number_t *out_hwirq, unsigned int *out_flags)  { @@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h,  	return 0;  } -static struct irq_host_ops socrates_fpga_pic_host_ops = { +static const struct irq_domain_ops socrates_fpga_pic_host_ops = {  	.map    = socrates_fpga_pic_host_map,  	.xlate  = socrates_fpga_pic_host_xlate,  }; @@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic)  	unsigned long flags;  	int i; -	/* Setup an irq_host structure */ -	socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR, -			SOCRATES_FPGA_NUM_IRQS,	&socrates_fpga_pic_host_ops, -			SOCRATES_FPGA_NUM_IRQS); +	/* Setup an irq_domain structure */ +	socrates_fpga_pic_irq_host = irq_domain_add_linear(pic, +		    SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);  	if (socrates_fpga_pic_irq_host == NULL) {  		pr_err("FPGA PIC: Unable to allocate host\n");  		return; diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 94594e58594..af3fd697de8 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -50,7 +50,7 @@  static DEFINE_RAW_SPINLOCK(gef_pic_lock);  static void __iomem *gef_pic_irq_reg_base; -static struct irq_host *gef_pic_irq_host; +static struct irq_domain *gef_pic_irq_host;  static int gef_pic_cascade_irq;  /* @@ -153,7 +153,7 @@ static struct irq_chip gef_pic_chip = {  /* When an interrupt is being configured, this call allows some flexibilty   * in deciding which irq_chip structure is used   */ -static int gef_pic_host_map(struct irq_host *h, unsigned int virq, +static int gef_pic_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hwirq)  {  	/* All interrupts are LEVEL sensitive */ @@ -163,7 +163,7 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct,  			    const u32 *intspec, unsigned int intsize,  			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)  { @@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops gef_pic_host_ops = { +static const struct irq_domain_ops gef_pic_host_ops = {  	.map	= gef_pic_host_map,  	.xlate	= gef_pic_host_xlate,  }; @@ -211,10 +211,9 @@ void __init gef_pic_init(struct device_node *np)  		return;  	} -	/* Setup an irq_host structure */ -	gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -					  GEF_PIC_NUM_IRQS, -					  &gef_pic_host_ops, NO_IRQ); +	/* Setup an irq_domain structure */ +	gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS, +					  &gef_pic_host_ops, NULL);  	if (gef_pic_irq_host == NULL)  		return; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 40a6e34793b..db360fc4cf0 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -67,7 +67,7 @@  struct axon_msic { -	struct irq_host *irq_host; +	struct irq_domain *irq_domain;  	__le32 *fifo_virt;  	dma_addr_t fifo_phys;  	dcr_host_t dcr_host; @@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)  static struct axon_msic *find_msi_translator(struct pci_dev *dev)  { -	struct irq_host *irq_host; +	struct irq_domain *irq_domain;  	struct device_node *dn, *tmp;  	const phandle *ph;  	struct axon_msic *msic = NULL; @@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)  		goto out_error;  	} -	irq_host = irq_find_host(dn); -	if (!irq_host) { -		dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n", +	irq_domain = irq_find_host(dn); +	if (!irq_domain) { +		dev_dbg(&dev->dev, "axon_msi: no irq_domain found for node %s\n",  			dn->full_name);  		goto out_error;  	} -	msic = irq_host->host_data; +	msic = irq_domain->host_data;  out_error:  	of_node_put(dn); @@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)  	BUILD_BUG_ON(NR_IRQS > 65536);  	list_for_each_entry(entry, &dev->msi_list, list) { -		virq = irq_create_direct_mapping(msic->irq_host); +		virq = irq_create_direct_mapping(msic->irq_domain);  		if (virq == NO_IRQ) {  			dev_warn(&dev->dev,  				 "axon_msi: virq allocation failed!\n"); @@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = {  	.name		= "AXON-MSI",  }; -static int msic_host_map(struct irq_host *h, unsigned int virq, +static int msic_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	irq_set_chip_data(virq, h->host_data); @@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops msic_host_ops = { +static const struct irq_domain_ops msic_host_ops = {  	.map	= msic_host_map,  }; @@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device)  	u32 tmp;  	pr_devel("axon_msi: disabling %s\n", -		  msic->irq_host->of_node->full_name); +		  msic->irq_domain->of_node->full_name);  	tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);  	tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;  	msic_dcr_write(msic, MSIC_CTRL_REG, tmp); @@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device)  	}  	memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES); -	msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP, -					NR_IRQS, &msic_host_ops, 0); -	if (!msic->irq_host) { -		printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", +	msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic); +	if (!msic->irq_domain) { +		printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n",  		       dn->full_name);  		goto out_free_fifo;  	} -	msic->irq_host->host_data = msic; -  	irq_set_handler_data(virq, msic);  	irq_set_chained_handler(virq, axon_msi_cascade);  	pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq); diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 55015e1f693..e5c3a2c6090 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);  static uint64_t	beatic_irq_mask_enable[(MAX_IRQS+255)/64];  static uint64_t	beatic_irq_mask_ack[(MAX_IRQS+255)/64]; -static struct irq_host *beatic_host; +static struct irq_domain *beatic_host;  /*   * In this implementation, "virq" == "IRQ plug number", @@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = {   *   * Note that the number (virq) is already assigned at upper layer.   */ -static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) +static void beatic_pic_host_unmap(struct irq_domain *h, unsigned int virq)  {  	beat_destruct_irq_plug(virq);  } @@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)   *   * Note that the number (virq) is already assigned at upper layer.   */ -static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, +static int beatic_pic_host_map(struct irq_domain *h, unsigned int virq,  			       irq_hw_number_t hw)  {  	int64_t	err; @@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,   * Called from irq_create_of_mapping() only.   * Note: We have only 1 entry to translate.   */ -static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int beatic_pic_host_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) +static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np)  {  	/* Match all */  	return 1;  } -static struct irq_host_ops beatic_pic_host_ops = { +static const struct irq_domain_ops beatic_pic_host_ops = {  	.map = beatic_pic_host_map,  	.unmap = beatic_pic_host_unmap,  	.xlate = beatic_pic_host_xlate, @@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void)  	ppc_md.get_irq = beatic_get_irq;  	/* Allocate an irq host */ -	beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -				     &beatic_pic_host_ops, -					 0); +	beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL);  	BUG_ON(beatic_host == NULL);  	irq_set_default_host(beatic_host);  } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 96a433dd2d6..2d42f3bb66d 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -56,7 +56,7 @@ struct iic {  static DEFINE_PER_CPU(struct iic, cpu_iic);  #define IIC_NODE_COUNT	2 -static struct irq_host *iic_host; +static struct irq_domain *iic_host;  /* Convert between "pending" bits and hw irq number */  static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) @@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg)  	out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);  } -struct irq_host *iic_get_irq_host(int node) +struct irq_domain *iic_get_irq_host(int node)  {  	return iic_host;  } @@ -222,13 +222,13 @@ void iic_request_IPIs(void)  #endif /* CONFIG_SMP */ -static int iic_host_match(struct irq_host *h, struct device_node *node) +static int iic_host_match(struct irq_domain *h, struct device_node *node)  {  	return of_device_is_compatible(node,  				    "IBM,CBEA-Internal-Interrupt-Controller");  } -static int iic_host_map(struct irq_host *h, unsigned int virq, +static int iic_host_map(struct irq_domain *h, unsigned int virq,  			irq_hw_number_t hw)  {  	switch (hw & IIC_IRQ_TYPE_MASK) { @@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int iic_host_xlate(struct irq_host *h, struct device_node *ct, +static int iic_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops iic_host_ops = { +static const struct irq_domain_ops iic_host_ops = {  	.match = iic_host_match,  	.map = iic_host_map,  	.xlate = iic_host_xlate, @@ -378,8 +378,8 @@ static int __init setup_iic(void)  void __init iic_init_IRQ(void)  {  	/* Setup an irq host data structure */ -	iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, -				  &iic_host_ops, IIC_IRQ_INVALID); +	iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops, +					 NULL);  	BUG_ON(iic_host == NULL);  	irq_set_default_host(iic_host); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 442c28c00f8..d8b7cc8a66c 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -62,7 +62,7 @@ enum {  #define SPIDER_IRQ_INVALID	63  struct spider_pic { -	struct irq_host		*host; +	struct irq_domain		*host;  	void __iomem		*regs;  	unsigned int		node_id;  }; @@ -168,7 +168,7 @@ static struct irq_chip spider_pic = {  	.irq_set_type = spider_set_irq_type,  }; -static int spider_host_map(struct irq_host *h, unsigned int virq, +static int spider_host_map(struct irq_domain *h, unsigned int virq,  			irq_hw_number_t hw)  {  	irq_set_chip_data(virq, h->host_data); @@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int spider_host_xlate(struct irq_host *h, struct device_node *ct, +static int spider_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops spider_host_ops = { +static const struct irq_domain_ops spider_host_ops = {  	.map = spider_host_map,  	.xlate = spider_host_xlate,  }; @@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip,  		panic("spider_pic: can't map registers !");  	/* Allocate a host */ -	pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR, -				   SPIDER_SRC_COUNT, &spider_host_ops, -				   SPIDER_IRQ_INVALID); +	pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT, +					  &spider_host_ops, pic);  	if (pic->host == NULL)  		panic("spider_pic: can't allocate irq host !"); -	pic->host->host_data = pic;  	/* Go through all sources and disable them */  	for (i = 0; i < SPIDER_SRC_COUNT; i++) { diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index f61a2dd96b9..53d6eee0196 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = {   *   */ -static struct irq_host *flipper_irq_host; +static struct irq_domain *flipper_irq_host; -static int flipper_pic_map(struct irq_host *h, unsigned int virq, +static int flipper_pic_map(struct irq_domain *h, unsigned int virq,  			   irq_hw_number_t hwirq)  {  	irq_set_chip_data(virq, h->host_data); @@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int flipper_pic_match(struct irq_host *h, struct device_node *np) +static int flipper_pic_match(struct irq_domain *h, struct device_node *np)  {  	return 1;  } -static struct irq_host_ops flipper_irq_host_ops = { +static const struct irq_domain_ops flipper_irq_domain_ops = {  	.map = flipper_pic_map,  	.match = flipper_pic_match,  }; @@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base)  	out_be32(io_base + FLIPPER_ICR, 0xffffffff);  } -struct irq_host * __init flipper_pic_init(struct device_node *np) +struct irq_domain * __init flipper_pic_init(struct device_node *np)  {  	struct device_node *pi; -	struct irq_host *irq_host = NULL; +	struct irq_domain *irq_domain = NULL;  	struct resource res;  	void __iomem *io_base;  	int retval; @@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np)  	__flipper_quiesce(io_base); -	irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, -				  &flipper_irq_host_ops, -1); -	if (!irq_host) { -		pr_err("failed to allocate irq_host\n"); +	irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS, +				  &flipper_irq_domain_ops, io_base); +	if (!irq_domain) { +		pr_err("failed to allocate irq_domain\n");  		return NULL;  	} -	irq_host->host_data = io_base; -  out: -	return irq_host; +	return irq_domain;  }  unsigned int flipper_pic_get_irq(void) diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index e4919170c6b..3006b5117ec 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = {   *   */ -static struct irq_host *hlwd_irq_host; +static struct irq_domain *hlwd_irq_host; -static int hlwd_pic_map(struct irq_host *h, unsigned int virq, +static int hlwd_pic_map(struct irq_domain *h, unsigned int virq,  			   irq_hw_number_t hwirq)  {  	irq_set_chip_data(virq, h->host_data); @@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops hlwd_irq_host_ops = { +static const struct irq_domain_ops hlwd_irq_domain_ops = {  	.map = hlwd_pic_map,  }; -static unsigned int __hlwd_pic_get_irq(struct irq_host *h) +static unsigned int __hlwd_pic_get_irq(struct irq_domain *h)  {  	void __iomem *io_base = h->host_data;  	int irq; @@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,  				      struct irq_desc *desc)  {  	struct irq_chip *chip = irq_desc_get_chip(desc); -	struct irq_host *irq_host = irq_get_handler_data(cascade_virq); +	struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq);  	unsigned int virq;  	raw_spin_lock(&desc->lock);  	chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */  	raw_spin_unlock(&desc->lock); -	virq = __hlwd_pic_get_irq(irq_host); +	virq = __hlwd_pic_get_irq(irq_domain);  	if (virq != NO_IRQ)  		generic_handle_irq(virq);  	else @@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base)  	out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff);  } -struct irq_host *hlwd_pic_init(struct device_node *np) +struct irq_domain *hlwd_pic_init(struct device_node *np)  { -	struct irq_host *irq_host; +	struct irq_domain *irq_domain;  	struct resource res;  	void __iomem *io_base;  	int retval; @@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np)  	__hlwd_quiesce(io_base); -	irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS, -				  &hlwd_irq_host_ops, -1); -	if (!irq_host) { -		pr_err("failed to allocate irq_host\n"); +	irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS, +					   &hlwd_irq_domain_ops, io_base); +	if (!irq_domain) { +		pr_err("failed to allocate irq_domain\n");  		return NULL;  	} -	irq_host->host_data = io_base; -	return irq_host; +	return irq_domain;  }  unsigned int hlwd_pic_get_irq(void) @@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void)  void hlwd_pic_probe(void)  { -	struct irq_host *host; +	struct irq_domain *host;  	struct device_node *np;  	const u32 *interrupts;  	int cascade_virq; diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index b2103453eb0..05ce5164caf 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -342,7 +342,7 @@ unsigned int iSeries_get_irq(void)  #ifdef CONFIG_PCI -static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, +static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq,  				irq_hw_number_t hw)  {  	irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); @@ -350,13 +350,13 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) +static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np)  {  	/* Match all */  	return 1;  } -static struct irq_host_ops iseries_irq_host_ops = { +static const struct irq_domain_ops iseries_irq_domain_ops = {  	.map = iseries_irq_host_map,  	.match = iseries_irq_host_match,  }; @@ -368,7 +368,7 @@ static struct irq_host_ops iseries_irq_host_ops = {  void __init iSeries_init_IRQ(void)  {  	/* Register PCI event handler and open an event path */ -	struct irq_host *host; +	struct irq_domain *host;  	int ret;  	/* @@ -380,8 +380,7 @@ void __init iSeries_init_IRQ(void)  	/* Create irq host. No need for a revmap since HV will give us  	 * back our virtual irq number  	 */ -	host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -			      &iseries_irq_host_ops, 0); +	host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL);  	BUG_ON(host == NULL);  	irq_set_default_host(host); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 7761aabfc29..92afc382a49 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock);  static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];  static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];  static int pmac_irq_cascade = -1; -static struct irq_host *pmac_pic_host; +static struct irq_domain *pmac_pic_host;  static void __pmac_retrigger(unsigned int irq_nr)  { @@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = {  	.name		= "cascade",  }; -static int pmac_pic_host_match(struct irq_host *h, struct device_node *node) +static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* We match all, we don't always have a node anyway */  	return 1;  } -static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, +static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq,  			     irq_hw_number_t hw)  {  	if (hw >= max_irqs) @@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, -			       const u32 *intspec, unsigned int intsize, -			       irq_hw_number_t *out_hwirq, -			       unsigned int *out_flags) - -{ -	*out_flags = IRQ_TYPE_NONE; -	*out_hwirq = *intspec; -	return 0; -} - -static struct irq_host_ops pmac_pic_host_ops = { +static const struct irq_domain_ops pmac_pic_host_ops = {  	.match = pmac_pic_host_match,  	.map = pmac_pic_host_map, -	.xlate = pmac_pic_host_xlate, +	.xlate = irq_domain_xlate_onecell,  };  static void __init pmac_pic_probe_oldstyle(void) @@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void)  	/*  	 * Allocate an irq host  	 */ -	pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs, -				       &pmac_pic_host_ops, -				       max_irqs); +	pmac_pic_host = irq_domain_add_linear(master, max_irqs, +					      &pmac_pic_host_ops, NULL);  	BUG_ON(pmac_pic_host == NULL);  	irq_set_default_host(pmac_pic_host); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 44d769258eb..a81e5a88fbd 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start;  static int psurge_type = PSURGE_NONE;  /* irq for secondary cpus to report */ -static struct irq_host *psurge_host; +static struct irq_domain *psurge_host;  int psurge_secondary_virq;  /* @@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data)  	psurge_set_ipi(cpu);  } -static int psurge_host_map(struct irq_host *h, unsigned int virq, +static int psurge_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq); @@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -struct irq_host_ops psurge_host_ops = { +static const struct irq_domain_ops psurge_host_ops = {  	.map	= psurge_host_map,  }; @@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void)  {  	int rc = -ENOMEM; -	psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -		&psurge_host_ops, 0); +	psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL);  	if (psurge_host)  		psurge_secondary_virq = irq_create_direct_mapping(psurge_host); diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 617efa12a3a..2a4ff86cc21 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,  static void dump_bmp(struct ps3_private* pd) {};  #endif /* defined(DEBUG) */ -static int ps3_host_map(struct irq_host *h, unsigned int virq, +static int ps3_host_map(struct irq_domain *h, unsigned int virq,  	irq_hw_number_t hwirq)  {  	DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, @@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int ps3_host_match(struct irq_host *h, struct device_node *np) +static int ps3_host_match(struct irq_domain *h, struct device_node *np)  {  	/* Match all */  	return 1;  } -static struct irq_host_ops ps3_host_ops = { +static const struct irq_domain_ops ps3_host_ops = {  	.map = ps3_host_map,  	.match = ps3_host_match,  }; @@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void)  {  	int result;  	unsigned cpu; -	struct irq_host *host; +	struct irq_domain *host; -	host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, -		PS3_INVALID_OUTLET); +	host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL);  	irq_set_default_host(host);  	irq_set_virq_count(PS3_PLUG_MAX + 1); diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index 19f353dfcd0..cb565bf9365 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -30,7 +30,7 @@  static int opb_index = 0;  struct opb_pic { -	struct irq_host *host; +	struct irq_domain *host;  	void *regs;  	int index;  	spinlock_t lock; @@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = {  	.irq_set_type	= opb_set_irq_type  }; -static int opb_host_map(struct irq_host *host, unsigned int virq, +static int opb_host_map(struct irq_domain *host, unsigned int virq,  		irq_hw_number_t hwirq)  {  	struct opb_pic *opb; @@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq,  	return 0;  } -static int opb_host_xlate(struct irq_host *host, struct device_node *dn, -		const u32 *intspec, unsigned int intsize, -		irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ -	/* Interrupt size must == 2 */ -	BUG_ON(intsize != 2); -	*out_hwirq = intspec[0]; -	*out_type = intspec[1]; -	return 0; -} - -static struct irq_host_ops opb_host_ops = { +static const struct irq_domain_ops opb_host_ops = {  	.map = opb_host_map, -	.xlate = opb_host_xlate, +	.xlate = irq_domain_xlate_twocell,  };  irqreturn_t opb_irq_handler(int irq, void *private) @@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)  		goto free_opb;  	} -	/* Allocate an irq host so that Linux knows that despite only +	/* Allocate an irq domain so that Linux knows that despite only  	 * having one interrupt to issue, we're the controller for multiple  	 * hardware IRQs, so later we can lookup their virtual IRQs. */ -	opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR, -			OPB_NR_IRQS, &opb_host_ops, -1); - +	opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb);  	if (!opb->host) {  		printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");  		goto free_regs; @@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)  	opb->index = opb_index++;  	spin_lock_init(&opb->lock); -	opb->host->host_data = opb;  	/* Disable all interrupts by default */  	opb_out(opb, OPB_MLSASIER, 0); diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 5d7d59a43c4..d4fa03f2b6a 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -54,7 +54,7 @@ cpm8xx_t __iomem *cpmp;  /* Pointer to comm processor space */  immap_t __iomem *mpc8xx_immr;  static cpic8xx_t __iomem *cpic_reg; -static struct irq_host *cpm_pic_host; +static struct irq_domain *cpm_pic_host;  static void cpm_mask_irq(struct irq_data *d)  { @@ -98,7 +98,7 @@ int cpm_get_irq(void)  	return irq_linear_revmap(cpm_pic_host, cpm_vec);  } -static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, +static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hw)  {  	pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = {  	.name = "error",  }; -static struct irq_host_ops cpm_pic_host_ops = { +static const struct irq_domain_ops cpm_pic_host_ops = {  	.map = cpm_pic_host_map,  }; @@ -164,8 +164,7 @@ unsigned int cpm_pic_init(void)  	out_be32(&cpic_reg->cpic_cimr, 0); -	cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -				      64, &cpm_pic_host_ops, 64); +	cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);  	if (cpm_pic_host == NULL) {  		printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");  		sirq = NO_IRQ; diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index bcab50e2a9e..d3be961e2ae 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -50,7 +50,7 @@  static intctl_cpm2_t __iomem *cpm2_intctl; -static struct irq_host *cpm2_pic_host; +static struct irq_domain *cpm2_pic_host;  #define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)  static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; @@ -214,7 +214,7 @@ unsigned int cpm2_get_irq(void)  	return irq_linear_revmap(cpm2_pic_host, irq);  } -static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, +static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hw)  {  	pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, -			    const u32 *intspec, unsigned int intsize, -			    irq_hw_number_t *out_hwirq, unsigned int *out_flags) -{ -	*out_hwirq = intspec[0]; -	if (intsize > 1) -		*out_flags = intspec[1]; -	else -		*out_flags = IRQ_TYPE_NONE; -	return 0; -} - -static struct irq_host_ops cpm2_pic_host_ops = { +static const struct irq_domain_ops cpm2_pic_host_ops = {  	.map = cpm2_pic_host_map, -	.xlate = cpm2_pic_host_xlate, +	.xlate = irq_domain_xlate_onetwocell,  };  void cpm2_pic_init(struct device_node *node) @@ -275,8 +263,7 @@ void cpm2_pic_init(struct device_node *node)  	out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);  	/* create a legacy host */ -	cpm2_pic_host = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, -				       64, &cpm2_pic_host_ops, 64); +	cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);  	if (cpm2_pic_host == NULL) {  		printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");  		return; diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index b6731e4a664..6e0e1005227 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -182,13 +182,13 @@ unsigned int ehv_pic_get_irq(void)  	return irq_linear_revmap(global_ehv_pic->irqhost, irq);  } -static int ehv_pic_host_match(struct irq_host *h, struct device_node *node) +static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* Exact match, unless ehv_pic node is NULL */  	return h->of_node == NULL || h->of_node == node;  } -static int ehv_pic_host_map(struct irq_host *h, unsigned int virq, +static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	struct ehv_pic *ehv_pic = h->host_data; @@ -217,7 +217,7 @@ static int ehv_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops ehv_pic_host_ops = { +static const struct irq_domain_ops ehv_pic_host_ops = {  	.match = ehv_pic_host_match,  	.map = ehv_pic_host_map,  	.xlate = ehv_pic_host_xlate, @@ -275,9 +275,8 @@ void __init ehv_pic_init(void)  		return;  	} -	ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -		NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0); - +	ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS, +						 &ehv_pic_host_ops, ehv_pic);  	if (!ehv_pic->irqhost) {  		of_node_put(np);  		kfree(ehv_pic); @@ -293,7 +292,6 @@ void __init ehv_pic_init(void)  		of_node_put(np2);  	} -	ehv_pic->irqhost->host_data = ehv_pic;  	ehv_pic->hc_irq = ehv_pic_irq_chip;  	ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;  	ehv_pic->coreint_flag = coreint_flag; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index ecb5c1946d2..0c01debe963 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -60,7 +60,7 @@ static struct irq_chip fsl_msi_chip = {  	.name		= "FSL-MSI",  }; -static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, +static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq,  				irq_hw_number_t hw)  {  	struct fsl_msi *msi_data = h->host_data; @@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops fsl_msi_host_ops = { +static const struct irq_domain_ops fsl_msi_host_ops = {  	.map = fsl_msi_host_map,  }; @@ -387,8 +387,8 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)  	}  	platform_set_drvdata(dev, msi); -	msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, -				      NR_MSI_IRQS, &fsl_msi_host_ops, 0); +	msi->irqhost = irq_domain_add_linear(dev->dev.of_node, +				      NR_MSI_IRQS, &fsl_msi_host_ops, msi);  	if (msi->irqhost == NULL) {  		dev_err(&dev->dev, "No memory for MSI irqhost\n"); @@ -420,8 +420,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)  	msi->feature = features->fsl_pic_ip; -	msi->irqhost->host_data = msi; -  	/*  	 * Remember the phandle, so that we can match with any PCI nodes  	 * that have an "fsl,msi" property. diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index f6c646a5254..8225f8653f7 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -26,7 +26,7 @@  #define FSL_PIC_IP_VMPIC  0x00000003  struct fsl_msi { -	struct irq_host *irqhost; +	struct irq_domain *irqhost;  	unsigned long cascade_irq; diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index d18bb27e4df..997df6a7ab5 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -25,7 +25,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff };  static DEFINE_RAW_SPINLOCK(i8259_lock); -static struct irq_host *i8259_host; +static struct irq_domain *i8259_host;  /*   * Acknowledge the IRQ using either the PCI host bridge's interrupt @@ -163,12 +163,12 @@ static struct resource pic_edgectrl_iores = {  	.flags = IORESOURCE_BUSY,  }; -static int i8259_host_match(struct irq_host *h, struct device_node *node) +static int i8259_host_match(struct irq_domain *h, struct device_node *node)  {  	return h->of_node == NULL || h->of_node == node;  } -static int i8259_host_map(struct irq_host *h, unsigned int virq, +static int i8259_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hw)  {  	pr_debug("i8259_host_map(%d, 0x%lx)\n", virq, hw); @@ -185,7 +185,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, +static int i8259_host_xlate(struct irq_domain *h, struct device_node *ct,  			    const u32 *intspec, unsigned int intsize,  			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)  { @@ -205,13 +205,13 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops i8259_host_ops = { +static struct irq_domain_ops i8259_host_ops = {  	.match = i8259_host_match,  	.map = i8259_host_map,  	.xlate = i8259_host_xlate,  }; -struct irq_host *i8259_get_host(void) +struct irq_domain *i8259_get_host(void)  {  	return i8259_host;  } @@ -263,8 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)  	raw_spin_unlock_irqrestore(&i8259_lock, flags);  	/* create a legacy host */ -	i8259_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY, -				    0, &i8259_host_ops, 0); +	i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL);  	if (i8259_host == NULL) {  		printk(KERN_ERR "i8259: failed to allocate irq host !\n");  		return; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 95da897f05a..b50f97811c2 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -672,13 +672,13 @@ static struct irq_chip ipic_edge_irq_chip = {  	.irq_set_type	= ipic_set_irq_type,  }; -static int ipic_host_match(struct irq_host *h, struct device_node *node) +static int ipic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* Exact match, unless ipic node is NULL */  	return h->of_node == NULL || h->of_node == node;  } -static int ipic_host_map(struct irq_host *h, unsigned int virq, +static int ipic_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	struct ipic *ipic = h->host_data; @@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, -			   const u32 *intspec, unsigned int intsize, -			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) - -{ -	/* interrupt sense values coming from the device tree equal either -	 * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change) -	 */ -	*out_hwirq = intspec[0]; -	if (intsize > 1) -		*out_flags = intspec[1]; -	else -		*out_flags = IRQ_TYPE_NONE; -	return 0; -} - -static struct irq_host_ops ipic_host_ops = { +static struct irq_domain_ops ipic_host_ops = {  	.match	= ipic_host_match,  	.map	= ipic_host_map, -	.xlate	= ipic_host_xlate, +	.xlate	= irq_domain_xlate_onetwocell,  };  struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) @@ -728,9 +712,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)  	if (ipic == NULL)  		return NULL; -	ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, -				       NR_IPIC_INTS, -				       &ipic_host_ops, 0); +	ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS, +					      &ipic_host_ops, ipic);  	if (ipic->irqhost == NULL) {  		kfree(ipic);  		return NULL; @@ -738,8 +721,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)  	ipic->regs = ioremap(res.start, resource_size(&res)); -	ipic->irqhost->host_data = ipic; -  	/* init hw */  	ipic_write(ipic->regs, IPIC_SICNR, 0x0); diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h index 9391c57b0c5..90031d1282e 100644 --- a/arch/powerpc/sysdev/ipic.h +++ b/arch/powerpc/sysdev/ipic.h @@ -43,7 +43,7 @@ struct ipic {  	volatile u32 __iomem	*regs;  	/* The remapper for this IPIC */ -	struct irq_host		*irqhost; +	struct irq_domain		*irqhost;  };  struct ipic_info { diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 2ca0a85fcce..d5f5416be31 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -17,7 +17,7 @@  extern int cpm_get_irq(struct pt_regs *regs); -static struct irq_host *mpc8xx_pic_host; +static struct irq_domain *mpc8xx_pic_host;  #define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)  static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];  static sysconf8xx_t __iomem *siu_reg; @@ -110,7 +110,7 @@ unsigned int mpc8xx_get_irq(void)  } -static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, +static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hw)  {  	pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -121,7 +121,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,  } -static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct,  			    const u32 *intspec, unsigned int intsize,  			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)  { @@ -142,7 +142,7 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,  } -static struct irq_host_ops mpc8xx_pic_host_ops = { +static struct irq_domain_ops mpc8xx_pic_host_ops = {  	.map = mpc8xx_pic_host_map,  	.xlate = mpc8xx_pic_host_xlate,  }; @@ -171,8 +171,7 @@ int mpc8xx_pic_init(void)  		goto out;  	} -	mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -					 64, &mpc8xx_pic_host_ops, 64); +	mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL);  	if (mpc8xx_pic_host == NULL) {  		printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");  		ret = -ENOMEM; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4e9ccb1015d..c83a512fa17 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = {  #endif /* CONFIG_MPIC_U3_HT_IRQS */ -static int mpic_host_match(struct irq_host *h, struct device_node *node) +static int mpic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* Exact match, unless mpic node is NULL */  	return h->of_node == NULL || h->of_node == node;  } -static int mpic_host_map(struct irq_host *h, unsigned int virq, +static int mpic_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	struct mpic *mpic = h->host_data; @@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc)  	BUG_ON(!(mpic->flags & MPIC_SECONDARY));  	virq = mpic_get_one_irq(mpic); -	if (virq != NO_IRQ) +	if (virq)  		generic_handle_irq(virq);  	chip->irq_eoi(&desc->irq_data);  } -static struct irq_host_ops mpic_host_ops = { +static struct irq_domain_ops mpic_host_ops = {  	.match = mpic_host_match,  	.map = mpic_host_map,  	.xlate = mpic_host_xlate, @@ -1345,10 +1345,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);  	mpic->isu_mask = (1 << mpic->isu_shift) - 1; -	mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR, +	mpic->irqhost = irq_domain_add_linear(mpic->node,  				       isu_size ? isu_size : mpic->num_sources, -				       &mpic_host_ops, -				       flags & MPIC_LARGE_VECTORS ? 2048 : 256); +				       &mpic_host_ops, mpic);  	/*  	 * FIXME: The code leaks the MPIC object and mappings here; this @@ -1357,8 +1356,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,  	if (mpic->irqhost == NULL)  		return NULL; -	mpic->irqhost->host_data = mpic; -  	/* Display version */  	switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) {  	case 1: diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 0f67cd79d48..0622aa91b18 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -32,7 +32,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)  static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)  {  	irq_hw_number_t hwirq; -	struct irq_host_ops *ops = mpic->irqhost->ops; +	const struct irq_domain_ops *ops = mpic->irqhost->ops;  	struct device_node *np;  	int flags, index, i;  	struct of_irq oirq; diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 14d130268e7..8848e99a83f 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -70,7 +70,7 @@ static u32 mv64x60_cached_low_mask;  static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS;  static u32 mv64x60_cached_gpp_mask; -static struct irq_host *mv64x60_irq_host; +static struct irq_domain *mv64x60_irq_host;  /*   * mv64x60_chip_low functions @@ -208,7 +208,7 @@ static struct irq_chip *mv64x60_chips[] = {  	[MV64x60_LEVEL1_GPP]  = &mv64x60_chip_gpp,  }; -static int mv64x60_host_map(struct irq_host *h, unsigned int virq, +static int mv64x60_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hwirq)  {  	int level1; @@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops mv64x60_host_ops = { +static struct irq_domain_ops mv64x60_host_ops = {  	.map   = mv64x60_host_map,  }; @@ -250,9 +250,8 @@ void __init mv64x60_init_irq(void)  	paddr = of_translate_address(np, reg);  	mv64x60_irq_reg_base = ioremap(paddr, reg[1]); -	mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -					  MV64x60_NUM_IRQS, -					  &mv64x60_host_ops, MV64x60_NUM_IRQS); +	mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS, +					  &mv64x60_host_ops, NULL);  	spin_lock_irqsave(&mv64x60_lock, flags);  	out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK, diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 73034bd203c..2fba6ef2f95 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -245,13 +245,13 @@ static struct irq_chip qe_ic_irq_chip = {  	.irq_mask_ack = qe_ic_mask_irq,  }; -static int qe_ic_host_match(struct irq_host *h, struct device_node *node) +static int qe_ic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* Exact match, unless qe_ic node is NULL */  	return h->of_node == NULL || h->of_node == node;  } -static int qe_ic_host_map(struct irq_host *h, unsigned int virq, +static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hw)  {  	struct qe_ic *qe_ic = h->host_data; @@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, -			    const u32 * intspec, unsigned int intsize, -			    irq_hw_number_t * out_hwirq, -			    unsigned int *out_flags) -{ -	*out_hwirq = intspec[0]; -	if (intsize > 1) -		*out_flags = intspec[1]; -	else -		*out_flags = IRQ_TYPE_NONE; -	return 0; -} - -static struct irq_host_ops qe_ic_host_ops = { +static struct irq_domain_ops qe_ic_host_ops = {  	.match = qe_ic_host_match,  	.map = qe_ic_host_map, -	.xlate = qe_ic_host_xlate, +	.xlate = irq_domain_xlate_onetwocell,  };  /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ @@ -339,8 +326,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,  	if (qe_ic == NULL)  		return; -	qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, -					NR_QE_IC_INTS, &qe_ic_host_ops, 0); +	qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, +					       &qe_ic_host_ops, qe_ic);  	if (qe_ic->irqhost == NULL) {  		kfree(qe_ic);  		return; @@ -348,7 +335,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,  	qe_ic->regs = ioremap(res.start, resource_size(&res)); -	qe_ic->irqhost->host_data = qe_ic;  	qe_ic->hc_irq = qe_ic_irq_chip;  	qe_ic->virq_high = irq_of_parse_and_map(node, 0); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h index c1361d005a8..c327872ed35 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.h +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h @@ -79,7 +79,7 @@ struct qe_ic {  	volatile u32 __iomem *regs;  	/* The remapper for this QEIC */ -	struct irq_host *irqhost; +	struct irq_domain *irqhost;  	/* The "linux" controller struct */  	struct irq_chip hc_irq; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 4d18658116e..188012c58f7 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -51,7 +51,7 @@  u32 tsi108_pci_cfg_base;  static u32 tsi108_pci_cfg_phys;  u32 tsi108_csr_vir_base; -static struct irq_host *pci_irq_host; +static struct irq_domain *pci_irq_host;  extern u32 get_vir_csrbase(void);  extern u32 tsi108_read_reg(u32 reg_offset); @@ -376,7 +376,7 @@ static struct irq_chip tsi108_pci_irq = {  	.irq_unmask = tsi108_pci_irq_unmask,  }; -static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, +static int pci_irq_host_xlate(struct irq_domain *h, struct device_node *ct,  			    const u32 *intspec, unsigned int intsize,  			    irq_hw_number_t *out_hwirq, unsigned int *out_flags)  { @@ -385,7 +385,7 @@ static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static int pci_irq_host_map(struct irq_host *h, unsigned int virq, +static int pci_irq_host_map(struct irq_domain *h, unsigned int virq,  			  irq_hw_number_t hw)  {	unsigned int irq;  	DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); @@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops pci_irq_host_ops = { +static struct irq_domain_ops pci_irq_domain_ops = {  	.map = pci_irq_host_map,  	.xlate = pci_irq_host_xlate,  }; @@ -419,10 +419,9 @@ void __init tsi108_pci_int_init(struct device_node *node)  {  	DBG("Tsi108_pci_int_init: initializing PCI interrupts\n"); -	pci_irq_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY, -				      0, &pci_irq_host_ops, 0); +	pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL);  	if (pci_irq_host == NULL) { -		printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n"); +		printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");  		return;  	} diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 063c901b126..92033936a8f 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -49,7 +49,7 @@ struct uic {  	raw_spinlock_t lock;  	/* The remapper for this UIC */ -	struct irq_host	*irqhost; +	struct irq_domain	*irqhost;  };  static void uic_unmask_irq(struct irq_data *d) @@ -174,7 +174,7 @@ static struct irq_chip uic_irq_chip = {  	.irq_set_type	= uic_set_irq_type,  }; -static int uic_host_map(struct irq_host *h, unsigned int virq, +static int uic_host_map(struct irq_domain *h, unsigned int virq,  			irq_hw_number_t hw)  {  	struct uic *uic = h->host_data; @@ -190,21 +190,9 @@ static int uic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int uic_host_xlate(struct irq_host *h, struct device_node *ct, -			  const u32 *intspec, unsigned int intsize, -			  irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ -	/* UIC intspecs must have 2 cells */ -	BUG_ON(intsize != 2); -	*out_hwirq = intspec[0]; -	*out_type = intspec[1]; -	return 0; -} - -static struct irq_host_ops uic_host_ops = { +static struct irq_domain_ops uic_host_ops = {  	.map	= uic_host_map, -	.xlate	= uic_host_xlate, +	.xlate	= irq_domain_xlate_twocell,  };  void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) @@ -270,13 +258,11 @@ static struct uic * __init uic_init_one(struct device_node *node)  	}  	uic->dcrbase = *dcrreg; -	uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, -				      NR_UIC_INTS, &uic_host_ops, -1); +	uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops, +					     uic);  	if (! uic->irqhost)  		return NULL; /* FIXME: panic? */ -	uic->irqhost->host_data = uic; -  	/* Start with all interrupts disabled, level and non-critical */  	mtdcr(uic->dcrbase + UIC_ER, 0);  	mtdcr(uic->dcrbase + UIC_CR, 0); diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index d72eda6a4c0..ea5e204e345 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -40,7 +40,7 @@ unsigned int xics_interrupt_server_size		= 8;  DEFINE_PER_CPU(struct xics_cppr, xics_cppr); -struct irq_host *xics_host; +struct irq_domain *xics_host;  static LIST_HEAD(ics_list); @@ -212,16 +212,16 @@ void xics_migrate_irqs_away(void)  		/* We can't set affinity on ISA interrupts */  		if (virq < NUM_ISA_INTERRUPTS)  			continue; -		if (!virq_is_host(virq, xics_host)) -			continue; -		irq = (unsigned int)virq_to_hw(virq); -		/* We need to get IPIs still. */ -		if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) -			continue;  		desc = irq_to_desc(virq);  		/* We only need to migrate enabled IRQS */  		if (!desc || !desc->action)  			continue; +		if (desc->irq_data.domain != xics_host) +			continue; +		irq = desc->irq_data.hwirq; +		/* We need to get IPIs still. */ +		if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) +			continue;  		chip = irq_desc_get_chip(desc);  		if (!chip || !chip->irq_set_affinity)  			continue; @@ -301,7 +301,7 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,  }  #endif /* CONFIG_SMP */ -static int xics_host_match(struct irq_host *h, struct device_node *node) +static int xics_host_match(struct irq_domain *h, struct device_node *node)  {  	struct ics *ics; @@ -323,7 +323,7 @@ static struct irq_chip xics_ipi_chip = {  	.irq_unmask = xics_ipi_unmask,  }; -static int xics_host_map(struct irq_host *h, unsigned int virq, +static int xics_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	struct ics *ics; @@ -351,7 +351,7 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,  	return -EINVAL;  } -static int xics_host_xlate(struct irq_host *h, struct device_node *ct, +static int xics_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -366,7 +366,7 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops xics_host_ops = { +static struct irq_domain_ops xics_host_ops = {  	.match = xics_host_match,  	.map = xics_host_map,  	.xlate = xics_host_xlate, @@ -374,8 +374,7 @@ static struct irq_host_ops xics_host_ops = {  static void __init xics_init_host(void)  { -	xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, -				   XICS_IRQ_SPURIOUS); +	xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL);  	BUG_ON(xics_host == NULL);  	irq_set_default_host(xics_host);  } diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 6183799754a..8d73c3c0bee 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -40,7 +40,7 @@  #define XINTC_IVR	24	/* Interrupt Vector */  #define XINTC_MER	28	/* Master Enable */ -static struct irq_host *master_irqhost; +static struct irq_domain *master_irqhost;  #define XILINX_INTC_MAXIRQS	(32) @@ -141,7 +141,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = {  /**   * xilinx_intc_xlate - translate virq# from device tree interrupts property   */ -static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, +static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct,  				const u32 *intspec, unsigned int intsize,  				irq_hw_number_t *out_hwirq,  				unsigned int *out_flags) @@ -161,7 +161,7 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static int xilinx_intc_map(struct irq_host *h, unsigned int virq, +static int xilinx_intc_map(struct irq_domain *h, unsigned int virq,  				  irq_hw_number_t irq)  {  	irq_set_chip_data(virq, h->host_data); @@ -177,15 +177,15 @@ static int xilinx_intc_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops xilinx_intc_ops = { +static struct irq_domain_ops xilinx_intc_ops = {  	.map = xilinx_intc_map,  	.xlate = xilinx_intc_xlate,  }; -struct irq_host * __init +struct irq_domain * __init  xilinx_intc_init(struct device_node *np)  { -	struct irq_host * irq; +	struct irq_domain * irq;  	void * regs;  	/* Find and map the intc registers */ @@ -200,12 +200,11 @@ xilinx_intc_init(struct device_node *np)  	out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */  	out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ -	/* Allocate and initialize an irq_host structure. */ -	irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS, -			     &xilinx_intc_ops, -1); +	/* Allocate and initialize an irq_domain structure. */ +	irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops, +				    regs);  	if (!irq)  		panic(__FILE__ ": Cannot allocate IRQ host\n"); -	irq->host_data = regs;  	return irq;  } diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index edd3d3cde46..c2876511070 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -22,6 +22,7 @@  #include <linux/proc_fs.h>  #include <linux/mutex.h>  #include <linux/atomic.h> +#include <linux/irqdomain.h>  #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT	2  #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT	1 @@ -55,15 +56,6 @@ struct resource;  extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);  extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); -/* These routines are here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes.  We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} -  extern struct device_node *of_console_device;  extern char *of_console_path;  extern char *of_console_options; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5bed94e189f..e0829a6a466 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -398,6 +398,7 @@ config X86_INTEL_CE  	select X86_REBOOTFIXUPS  	select OF  	select OF_EARLY_FLATTREE +	select IRQ_DOMAIN  	---help---  	  Select for the Intel CE media processor (CE4100) SOC.  	  This option compiles in support for the CE4100 SOC for settop @@ -2076,6 +2077,7 @@ config OLPC  	select GPIOLIB  	select OF  	select OF_PROMTREE +	select IRQ_DOMAIN  	---help---  	  Add support for detecting the unique features of the OLPC  	  XO hardware. diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h deleted file mode 100644 index 423bbbddf36..00000000000 --- a/arch/x86/include/asm/irq_controller.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __IRQ_CONTROLLER__ -#define __IRQ_CONTROLLER__ - -struct irq_domain { -	int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize, -			u32 *out_hwirq, u32 *out_type); -	void *priv; -	struct device_node *controller; -	struct list_head l; -}; - -#endif diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h index 644dd885f05..60bef663609 100644 --- a/arch/x86/include/asm/prom.h +++ b/arch/x86/include/asm/prom.h @@ -21,7 +21,6 @@  #include <asm/irq.h>  #include <linux/atomic.h>  #include <asm/setup.h> -#include <asm/irq_controller.h>  #ifdef CONFIG_OF  extern int of_ioapic; @@ -43,15 +42,6 @@ extern char cmd_line[COMMAND_LINE_SIZE];  #define pci_address_to_pio pci_address_to_pio  unsigned long pci_address_to_pio(phys_addr_t addr); -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - * - * FIXME: We really should implement proper virq handling like power, - * but that's going to be major surgery. - */ -static inline void irq_dispose_mapping(unsigned int virq) { } -  #define HAVE_ARCH_DEVTREE_FIXUPS  #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 52821799a70..3ae2ced4a87 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -4,6 +4,7 @@  #include <linux/bootmem.h>  #include <linux/export.h>  #include <linux/io.h> +#include <linux/irqdomain.h>  #include <linux/interrupt.h>  #include <linux/list.h>  #include <linux/of.h> @@ -17,64 +18,14 @@  #include <linux/initrd.h>  #include <asm/hpet.h> -#include <asm/irq_controller.h>  #include <asm/apic.h>  #include <asm/pci_x86.h>  __initdata u64 initial_dtb;  char __initdata cmd_line[COMMAND_LINE_SIZE]; -static LIST_HEAD(irq_domains); -static DEFINE_RAW_SPINLOCK(big_irq_lock);  int __initdata of_ioapic; -#ifdef CONFIG_X86_IO_APIC -static void add_interrupt_host(struct irq_domain *ih) -{ -	unsigned long flags; - -	raw_spin_lock_irqsave(&big_irq_lock, flags); -	list_add(&ih->l, &irq_domains); -	raw_spin_unlock_irqrestore(&big_irq_lock, flags); -} -#endif - -static struct irq_domain *get_ih_from_node(struct device_node *controller) -{ -	struct irq_domain *ih, *found = NULL; -	unsigned long flags; - -	raw_spin_lock_irqsave(&big_irq_lock, flags); -	list_for_each_entry(ih, &irq_domains, l) { -		if (ih->controller ==  controller) { -			found = ih; -			break; -		} -	} -	raw_spin_unlock_irqrestore(&big_irq_lock, flags); -	return found; -} - -unsigned int irq_create_of_mapping(struct device_node *controller, -				   const u32 *intspec, unsigned int intsize) -{ -	struct irq_domain *ih; -	u32 virq, type; -	int ret; - -	ih = get_ih_from_node(controller); -	if (!ih) -		return 0; -	ret = ih->xlate(ih, intspec, intsize, &virq, &type); -	if (ret) -		return 0; -	if (type == IRQ_TYPE_NONE) -		return virq; -	irq_set_irq_type(virq, type); -	return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); -  unsigned long pci_address_to_pio(phys_addr_t address)  {  	/* @@ -354,36 +305,43 @@ static struct of_ioapic_type of_ioapic_type[] =  	},  }; -static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, -			u32 *out_hwirq, u32 *out_type) +static int ioapic_xlate(struct irq_domain *domain, +			struct device_node *controller, +			const u32 *intspec, u32 intsize, +			irq_hw_number_t *out_hwirq, u32 *out_type)  { -	struct mp_ioapic_gsi *gsi_cfg;  	struct io_apic_irq_attr attr;  	struct of_ioapic_type *it; -	u32 line, idx, type; +	u32 line, idx; +	int rc; -	if (intsize < 2) +	if (WARN_ON(intsize < 2))  		return -EINVAL; -	line = *intspec; -	idx = (u32) id->priv; -	gsi_cfg = mp_ioapic_gsi_routing(idx); -	*out_hwirq = line + gsi_cfg->gsi_base; - -	intspec++; -	type = *intspec; +	line = intspec[0]; -	if (type >= ARRAY_SIZE(of_ioapic_type)) +	if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))  		return -EINVAL; -	it = of_ioapic_type + type; -	*out_type = it->out_type; +	it = &of_ioapic_type[intspec[1]]; +	idx = (u32) domain->host_data;  	set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); -	return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr); +	rc = io_apic_setup_irq_pin_once(irq_find_mapping(domain, line), +					cpu_to_node(0), &attr); +	if (rc) +		return rc; + +	*out_hwirq = line; +	*out_type = it->out_type; +	return 0;  } +const struct irq_domain_ops ioapic_irq_domain_ops = { +	.xlate = ioapic_xlate, +}; +  static void __init ioapic_add_ofnode(struct device_node *np)  {  	struct resource r; @@ -399,13 +357,14 @@ static void __init ioapic_add_ofnode(struct device_node *np)  	for (i = 0; i < nr_ioapics; i++) {  		if (r.start == mpc_ioapic_addr(i)) {  			struct irq_domain *id; +			struct mp_ioapic_gsi *gsi_cfg; + +			gsi_cfg = mp_ioapic_gsi_routing(i); -			id = kzalloc(sizeof(*id), GFP_KERNEL); +			id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0, +						   &ioapic_irq_domain_ops, +						   (void*)i);  			BUG_ON(!id); -			id->controller = np; -			id->xlate = ioapic_xlate; -			id->priv = (void *)i; -			add_interrupt_host(id);  			return;  		}  	} diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 5cd04b65c55..e6568c19c93 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -37,7 +37,7 @@ struct mpc8xxx_gpio_chip {  	 * open drain mode safely  	 */  	u32 data; -	struct irq_host *irq; +	struct irq_domain *irq;  	void *of_dev_id_data;  }; @@ -281,7 +281,7 @@ static struct irq_chip mpc8xxx_irq_chip = {  	.irq_set_type	= mpc8xxx_irq_set_type,  }; -static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, +static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq,  				irq_hw_number_t hw)  {  	struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; @@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, -				  const u32 *intspec, unsigned int intsize, -				  irq_hw_number_t *out_hwirq, -				  unsigned int *out_flags) - -{ -	/* interrupt sense values coming from the device tree equal either -	 * EDGE_FALLING or EDGE_BOTH -	 */ -	*out_hwirq = intspec[0]; -	*out_flags = intspec[1]; - -	return 0; -} - -static struct irq_host_ops mpc8xxx_gpio_irq_ops = { +static struct irq_domain_ops mpc8xxx_gpio_irq_ops = {  	.map	= mpc8xxx_gpio_irq_map, -	.xlate	= mpc8xxx_gpio_irq_xlate, +	.xlate	= irq_domain_xlate_twocell,  };  static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { @@ -364,9 +349,8 @@ static void __init mpc8xxx_add_controller(struct device_node *np)  	if (hwirq == NO_IRQ)  		goto skip_irq; -	mpc8xxx_gc->irq = -		irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, -			       &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); +	mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, +					&mpc8xxx_gpio_irq_ops, mpc8xxx_gc);  	if (!mpc8xxx_gc->irq)  		goto skip_irq; @@ -374,8 +358,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np)  	if (id)  		mpc8xxx_gc->of_dev_id_data = id->data; -	mpc8xxx_gc->irq->host_data = mpc8xxx_gc; -  	/* ack and mask all irqs */  	out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);  	out_be32(mm_gc->regs + GPIO_IMR, 0); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f147395bac9..1489c3540f9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -201,6 +201,7 @@ config MENELAUS  config TWL4030_CORE  	bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"  	depends on I2C=y && GENERIC_HARDIRQS +	select IRQ_DOMAIN  	help  	  Say yes here if you have TWL4030 / TWL6030 family chip on your board.  	  This core driver provides register access and IRQ handling diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 8ce3959c691..4970d43952d 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -149,7 +149,7 @@  #define TWL_MODULE_LAST TWL4030_MODULE_LAST -#define TWL4030_NR_IRQS    8 +#define TWL4030_NR_IRQS    34 /* core:8, power:8, gpio: 18 */  #define TWL6030_NR_IRQS    20  /* Base Address defns for twl4030_map[] */ @@ -263,10 +263,6 @@ struct twl_client {  static struct twl_client twl_modules[TWL_NUM_SLAVES]; -#ifdef CONFIG_IRQ_DOMAIN -static struct irq_domain domain; -#endif -  /* mapping the module id to slave id and base address */  struct twl_mapping {  	unsigned char sid;	/* Slave ID */ @@ -1227,14 +1223,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)  	pdata->irq_base = status;  	pdata->irq_end = pdata->irq_base + nr_irqs; - -#ifdef CONFIG_IRQ_DOMAIN -	domain.irq_base = pdata->irq_base; -	domain.nr_irq = nr_irqs; -	domain.of_node = of_node_get(node); -	domain.ops = &irq_domain_simple_ops; -	irq_domain_add(&domain); -#endif +	irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0, +			      &irq_domain_simple_ops, NULL);  	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {  		dev_dbg(&client->dev, "can't talk I2C?\n"); @@ -1315,11 +1305,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)  		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);  	} -#ifdef CONFIG_OF_DEVICE +	status = -ENODEV;  	if (node)  		status = of_platform_populate(node, NULL, NULL, &client->dev); -	else -#endif +	if (status)  		status = add_children(pdata, id->driver_data);  fail: diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 50e8e5e7446..7189adf54bd 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -255,13 +255,13 @@ static inline int __init mdio_ofgpio_init(void)  	return platform_driver_register(&mdio_ofgpio_driver);  } -static inline void __exit mdio_ofgpio_exit(void) +static inline void mdio_ofgpio_exit(void)  {  	platform_driver_unregister(&mdio_ofgpio_driver);  }  #else  static inline int __init mdio_ofgpio_init(void) { return 0; } -static inline void __exit mdio_ofgpio_exit(void) { } +static inline void mdio_ofgpio_exit(void) { }  #endif /* CONFIG_OF_GPIO */  static struct platform_driver mdio_gpio_driver = { diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 63b3ec48c20..20fbebd49db 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -55,7 +55,7 @@ EXPORT_SYMBOL(of_find_device_by_node);  #include <asm/dcr.h>  #endif -#if !defined(CONFIG_SPARC) +#ifdef CONFIG_OF_ADDRESS  /*   * The following routines scan a subtree and registers a device for   * each applicable node. @@ -462,4 +462,4 @@ int of_platform_populate(struct device_node *root,  	of_node_put(root);  	return rc;  } -#endif /* !CONFIG_SPARC */ +#endif /* CONFIG_OF_ADDRESS */ diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index bd4272b61a1..ead4a421579 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -9,99 +9,182 @@   * representation into a hardware irq number that can be mapped back to a   * Linux irq number without any extra platform support code.   * - * irq_domain is expected to be embedded in an interrupt controller's private - * data structure. + * Interrupt controller "domain" data structure. This could be defined as a + * irq domain controller. That is, it handles the mapping between hardware + * and virtual interrupt numbers for a given interrupt domain. The domain + * structure is generally created by the PIC code for a given PIC instance + * (though a domain can cover more than one PIC if they have a flat number + * model). It's the domain callbacks that are responsible for setting the + * irq_chip on a given irq_desc after it's been mapped. + * + * The host code and data structures are agnostic to whether or not + * we use an open firmware device-tree. We do have references to struct + * device_node in two places: in irq_find_host() to find the host matching + * a given interrupt controller node, and of course as an argument to its + * counterpart domain->ops->match() callback. However, those are treated as + * generic pointers by the core and the fact that it's actually a device-node + * pointer is purely a convention between callers and implementation. This + * code could thus be used on other architectures by replacing those two + * by some sort of arch-specific void * "token" used to identify interrupt + * controllers.   */ +  #ifndef _LINUX_IRQDOMAIN_H  #define _LINUX_IRQDOMAIN_H -#include <linux/irq.h> -#include <linux/mod_devicetable.h> +#include <linux/types.h> +#include <linux/radix-tree.h> -#ifdef CONFIG_IRQ_DOMAIN  struct device_node;  struct irq_domain; +struct of_device_id; + +/* Number of irqs reserved for a legacy isa controller */ +#define NUM_ISA_INTERRUPTS	16 + +/* This type is the placeholder for a hardware interrupt number. It has to + * be big enough to enclose whatever representation is used by a given + * platform. + */ +typedef unsigned long irq_hw_number_t;  /**   * struct irq_domain_ops - Methods for irq_domain objects - * @to_irq: (optional) given a local hardware irq number, return the linux - *          irq number.  If to_irq is not implemented, then the irq_domain - *          will use this translation: irq = (domain->irq_base + hwirq) - * @dt_translate: Given a device tree node and interrupt specifier, decode - *                the hardware irq number and linux irq type value. + * @match: Match an interrupt controller device node to a host, returns + *         1 on a match + * @map: Create or update a mapping between a virtual irq number and a hw + *       irq number. This is called only once for a given mapping. + * @unmap: Dispose of such a mapping + * @xlate: Given a device tree node and interrupt specifier, decode + *         the hardware irq number and linux irq type value. + * + * Functions below are provided by the driver and called whenever a new mapping + * is created or an old mapping is disposed. The driver can then proceed to + * whatever internal data structures management is required. It also needs + * to setup the irq_desc when returning from map().   */  struct irq_domain_ops { -	unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq); - -#ifdef CONFIG_OF -	int (*dt_translate)(struct irq_domain *d, struct device_node *node, -			    const u32 *intspec, unsigned int intsize, -			    unsigned long *out_hwirq, unsigned int *out_type); -#endif /* CONFIG_OF */ +	int (*match)(struct irq_domain *d, struct device_node *node); +	int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); +	void (*unmap)(struct irq_domain *d, unsigned int virq); +	int (*xlate)(struct irq_domain *d, struct device_node *node, +		     const u32 *intspec, unsigned int intsize, +		     unsigned long *out_hwirq, unsigned int *out_type);  };  /**   * struct irq_domain - Hardware interrupt number translation object - * @list: Element in global irq_domain list. + * @link: Element in global irq_domain list. + * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This + *               will be one of the IRQ_DOMAIN_MAP_* values. + * @revmap_data: Revmap method specific data. + * @ops: pointer to irq_domain methods + * @host_data: private data pointer for use by owner.  Not touched by irq_domain + *             core code.   * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator   *            of the irq_domain is responsible for allocating the array of   *            irq_desc structures.   * @nr_irq: Number of irqs managed by the irq domain   * @hwirq_base: Starting number for hwirqs managed by the irq domain - * @ops: pointer to irq_domain methods - * @priv: private data pointer for use by owner.  Not touched by irq_domain - *        core code.   * @of_node: (optional) Pointer to device tree nodes associated with the   *           irq_domain.  Used when decoding device tree interrupt specifiers.   */  struct irq_domain { -	struct list_head list; -	unsigned int irq_base; -	unsigned int nr_irq; -	unsigned int hwirq_base; +	struct list_head link; + +	/* type of reverse mapping_technique */ +	unsigned int revmap_type; +	union { +		struct { +			unsigned int size; +			unsigned int first_irq; +			irq_hw_number_t first_hwirq; +		} legacy; +		struct { +			unsigned int size; +			unsigned int *revmap; +		} linear; +		struct radix_tree_root tree; +	} revmap_data;  	const struct irq_domain_ops *ops; -	void *priv; +	void *host_data; +	irq_hw_number_t inval_irq; + +	/* Optional device node pointer */  	struct device_node *of_node;  }; -/** - * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number - * - * Returns the linux irq number associated with a hardware irq.  By default, - * the mapping is irq == domain->irq_base + hwirq, but this mapping can - * be overridden if the irq_domain implements a .to_irq() hook. - */ -static inline unsigned int irq_domain_to_irq(struct irq_domain *d, -					     unsigned long hwirq) +#ifdef CONFIG_IRQ_DOMAIN +struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, +					 unsigned int size, +					 unsigned int first_irq, +					 irq_hw_number_t first_hwirq, +					 const struct irq_domain_ops *ops, +					 void *host_data); +struct irq_domain *irq_domain_add_linear(struct device_node *of_node, +					 unsigned int size, +					 const struct irq_domain_ops *ops, +					 void *host_data); +struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, +					 const struct irq_domain_ops *ops, +					 void *host_data); +struct irq_domain *irq_domain_add_tree(struct device_node *of_node, +					 const struct irq_domain_ops *ops, +					 void *host_data); + +extern struct irq_domain *irq_find_host(struct device_node *node); +extern void irq_set_default_host(struct irq_domain *host); +extern void irq_set_virq_count(unsigned int count); + +static inline struct irq_domain *irq_domain_add_legacy_isa( +				struct device_node *of_node, +				const struct irq_domain_ops *ops, +				void *host_data)  { -	if (d->ops->to_irq) -		return d->ops->to_irq(d, hwirq); -	if (WARN_ON(hwirq < d->hwirq_base)) -		return 0; -	return d->irq_base + hwirq - d->hwirq_base; +	return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, +				     host_data);  } +extern struct irq_domain *irq_find_host(struct device_node *node); +extern void irq_set_default_host(struct irq_domain *host); +extern void irq_set_virq_count(unsigned int count); -#define irq_domain_for_each_hwirq(d, hw) \ -	for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++) -#define irq_domain_for_each_irq(d, hw, irq) \ -	for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \ -	     hw < d->hwirq_base + d->nr_irq; \ -	     hw++, irq = irq_domain_to_irq(d, hw)) +extern unsigned int irq_create_mapping(struct irq_domain *host, +				       irq_hw_number_t hwirq); +extern void irq_dispose_mapping(unsigned int virq); +extern unsigned int irq_find_mapping(struct irq_domain *host, +				     irq_hw_number_t hwirq); +extern unsigned int irq_create_direct_mapping(struct irq_domain *host); +extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, +				    irq_hw_number_t hwirq); +extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, +					    irq_hw_number_t hwirq); +extern unsigned int irq_linear_revmap(struct irq_domain *host, +				      irq_hw_number_t hwirq); -extern void irq_domain_add(struct irq_domain *domain); -extern void irq_domain_del(struct irq_domain *domain); +extern const struct irq_domain_ops irq_domain_simple_ops; -extern struct irq_domain_ops irq_domain_simple_ops; -#endif /* CONFIG_IRQ_DOMAIN */ +/* stock xlate functions */ +int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, +			const u32 *intspec, unsigned int intsize, +			irq_hw_number_t *out_hwirq, unsigned int *out_type); +int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, +			const u32 *intspec, unsigned int intsize, +			irq_hw_number_t *out_hwirq, unsigned int *out_type); +int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, +			const u32 *intspec, unsigned int intsize, +			irq_hw_number_t *out_hwirq, unsigned int *out_type); -#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ) -extern void irq_domain_add_simple(struct device_node *controller, int irq_base); +#if defined(CONFIG_OF_IRQ)  extern void irq_domain_generate_simple(const struct of_device_id *match,  					u64 phys_base, unsigned int irq_start); -#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */ +#else /* CONFIG_OF_IRQ */  static inline void irq_domain_generate_simple(const struct of_device_id *match,  					u64 phys_base, unsigned int irq_start) { } -#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */ +#endif /* !CONFIG_OF_IRQ */ + +#else /* CONFIG_IRQ_DOMAIN */ +static inline void irq_dispose_mapping(unsigned int virq) { } +#endif /* !CONFIG_IRQ_DOMAIN */  #endif /* _LINUX_IRQDOMAIN_H */ diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 3118623c2c1..01b925ad8d7 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -4,6 +4,7 @@  #include <linux/errno.h>  #include <linux/of.h> +#ifdef CONFIG_OF_ADDRESS  extern u64 of_translate_address(struct device_node *np, const __be32 *addr);  extern int of_address_to_resource(struct device_node *dev, int index,  				  struct resource *r); @@ -25,12 +26,37 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; }  #define pci_address_to_pio pci_address_to_pio  #endif -#ifdef CONFIG_PCI +#else /* CONFIG_OF_ADDRESS */ +static inline int of_address_to_resource(struct device_node *dev, int index, +					 struct resource *r) +{ +	return -EINVAL; +} +static inline struct device_node *of_find_matching_node_by_address( +					struct device_node *from, +					const struct of_device_id *matches, +					u64 base_address) +{ +	return NULL; +} +static inline void __iomem *of_iomap(struct device_node *device, int index) +{ +	return NULL; +} +static inline const u32 *of_get_address(struct device_node *dev, int index, +					u64 *size, unsigned int *flags) +{ +	return NULL; +} +#endif /* CONFIG_OF_ADDRESS */ + + +#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI)  extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no,  			       u64 *size, unsigned int *flags);  extern int of_pci_address_to_resource(struct device_node *dev, int bar,  				      struct resource *r); -#else /* CONFIG_PCI */ +#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */  static inline int of_pci_address_to_resource(struct device_node *dev, int bar,  				             struct resource *r)  { @@ -42,8 +68,7 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev,  {  	return NULL;  } -#endif /* CONFIG_PCI */ - +#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */  #endif /* __OF_ADDRESS_H */ diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index d0307eed20c..d229ad3edee 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -6,6 +6,7 @@ struct of_irq;  #include <linux/types.h>  #include <linux/errno.h>  #include <linux/irq.h> +#include <linux/irqdomain.h>  #include <linux/ioport.h>  #include <linux/of.h> @@ -65,9 +66,6 @@ extern int of_irq_map_one(struct device_node *device, int index,  extern unsigned int irq_create_of_mapping(struct device_node *controller,  					  const u32 *intspec,  					  unsigned int intsize); -#ifdef CONFIG_IRQ_DOMAIN -extern void irq_dispose_mapping(unsigned int irq); -#endif  extern int of_irq_to_resource(struct device_node *dev, int index,  			      struct resource *r);  extern int of_irq_count(struct device_node *dev); diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 040ce2f6e8d..242fa3563e2 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -81,7 +81,7 @@ extern struct platform_device *of_device_alloc(struct device_node *np,  					 struct device *parent);  extern struct platform_device *of_find_device_by_node(struct device_node *np); -#if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */ +#ifdef CONFIG_OF_ADDRESS /* device reg helpers depend on OF_ADDRESS */  /* Platform devices and busses creation */  extern struct platform_device *of_platform_device_create(struct device_node *np,  						   const char *bus_id, @@ -94,7 +94,15 @@ extern int of_platform_populate(struct device_node *root,  				const struct of_device_id *matches,  				const struct of_dev_auxdata *lookup,  				struct device *parent); -#endif /* !CONFIG_SPARC */ +#else +static inline int of_platform_populate(struct device_node *root, +					const struct of_device_id *matches, +					const struct of_dev_auxdata *lookup, +					struct device *parent) +{ +	return -ENODEV; +} +#endif /* !CONFIG_OF_ADDRESS */  #endif /* CONFIG_OF_DEVICE */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 1f9e26526b6..af48e59bc2f 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1,189 +1,793 @@ +#include <linux/debugfs.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h>  #include <linux/irq.h> +#include <linux/irqdesc.h>  #include <linux/irqdomain.h>  #include <linux/module.h>  #include <linux/mutex.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/seq_file.h>  #include <linux/slab.h> +#include <linux/smp.h> +#include <linux/fs.h> + +#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs. +				 * ie. legacy 8259, gets irqs 1..15 */ +#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */ +#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */ +#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */  static LIST_HEAD(irq_domain_list);  static DEFINE_MUTEX(irq_domain_mutex); +static DEFINE_MUTEX(revmap_trees_mutex); +static unsigned int irq_virq_count = NR_IRQS; +static struct irq_domain *irq_default_domain; +  /** - * irq_domain_add() - Register an irq_domain - * @domain: ptr to initialized irq_domain structure + * irq_domain_alloc() - Allocate a new irq_domain data structure + * @of_node: optional device-tree node of the interrupt controller + * @revmap_type: type of reverse mapping to use + * @ops: map/unmap domain callbacks + * @host_data: Controller private data pointer   * - * Registers an irq_domain structure.  The irq_domain must at a minimum be - * initialized with an ops structure pointer, and either a ->to_irq hook or - * a valid irq_base value.  Everything else is optional. + * Allocates and initialize and irq_domain structure.  Caller is expected to + * register allocated irq_domain with irq_domain_register().  Returns pointer + * to IRQ domain, or NULL on failure.   */ -void irq_domain_add(struct irq_domain *domain) +static struct irq_domain *irq_domain_alloc(struct device_node *of_node, +					   unsigned int revmap_type, +					   const struct irq_domain_ops *ops, +					   void *host_data)  { -	struct irq_data *d; -	int hwirq, irq; +	struct irq_domain *domain; -	/* -	 * This assumes that the irq_domain owner has already allocated -	 * the irq_descs.  This block will be removed when support for dynamic -	 * allocation of irq_descs is added to irq_domain. -	 */ -	irq_domain_for_each_irq(domain, hwirq, irq) { -		d = irq_get_irq_data(irq); -		if (!d) { -			WARN(1, "error: assigning domain to non existant irq_desc"); -			return; -		} -		if (d->domain) { -			/* things are broken; just report, don't clean up */ -			WARN(1, "error: irq_desc already assigned to a domain"); -			return; +	domain = kzalloc(sizeof(*domain), GFP_KERNEL); +	if (WARN_ON(!domain)) +		return NULL; + +	/* Fill structure */ +	domain->revmap_type = revmap_type; +	domain->ops = ops; +	domain->host_data = host_data; +	domain->of_node = of_node_get(of_node); + +	return domain; +} + +static void irq_domain_add(struct irq_domain *domain) +{ +	mutex_lock(&irq_domain_mutex); +	list_add(&domain->link, &irq_domain_list); +	mutex_unlock(&irq_domain_mutex); +	pr_debug("irq: Allocated domain of type %d @0x%p\n", +		 domain->revmap_type, domain); +} + +static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, +					     irq_hw_number_t hwirq) +{ +	irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq; +	int size = domain->revmap_data.legacy.size; + +	if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size)) +		return 0; +	return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq; +} + +/** + * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain. + * @of_node: pointer to interrupt controller's device tree node. + * @size: total number of irqs in legacy mapping + * @first_irq: first number of irq block assigned to the domain + * @first_hwirq: first hwirq number to use for the translation. Should normally + *               be '0', but a positive integer can be used if the effective + *               hwirqs numbering does not begin at zero. + * @ops: map/unmap domain callbacks + * @host_data: Controller private data pointer + * + * Note: the map() callback will be called before this function returns + * for all legacy interrupts except 0 (which is always the invalid irq for + * a legacy controller). + */ +struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, +					 unsigned int size, +					 unsigned int first_irq, +					 irq_hw_number_t first_hwirq, +					 const struct irq_domain_ops *ops, +					 void *host_data) +{ +	struct irq_domain *domain; +	unsigned int i; + +	domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data); +	if (!domain) +		return NULL; + +	domain->revmap_data.legacy.first_irq = first_irq; +	domain->revmap_data.legacy.first_hwirq = first_hwirq; +	domain->revmap_data.legacy.size = size; + +	mutex_lock(&irq_domain_mutex); +	/* Verify that all the irqs are available */ +	for (i = 0; i < size; i++) { +		int irq = first_irq + i; +		struct irq_data *irq_data = irq_get_irq_data(irq); + +		if (WARN_ON(!irq_data || irq_data->domain)) { +			mutex_unlock(&irq_domain_mutex); +			of_node_put(domain->of_node); +			kfree(domain); +			return NULL;  		} -		d->domain = domain; -		d->hwirq = hwirq;  	} -	mutex_lock(&irq_domain_mutex); -	list_add(&domain->list, &irq_domain_list); +	/* Claim all of the irqs before registering a legacy domain */ +	for (i = 0; i < size; i++) { +		struct irq_data *irq_data = irq_get_irq_data(first_irq + i); +		irq_data->hwirq = first_hwirq + i; +		irq_data->domain = domain; +	}  	mutex_unlock(&irq_domain_mutex); + +	for (i = 0; i < size; i++) { +		int irq = first_irq + i; +		int hwirq = first_hwirq + i; + +		/* IRQ0 gets ignored */ +		if (!irq) +			continue; + +		/* Legacy flags are left to default at this point, +		 * one can then use irq_create_mapping() to +		 * explicitly change them +		 */ +		ops->map(domain, irq, hwirq); + +		/* Clear norequest flags */ +		irq_clear_status_flags(irq, IRQ_NOREQUEST); +	} + +	irq_domain_add(domain); +	return domain; +} + +/** + * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain. + * @of_node: pointer to interrupt controller's device tree node. + * @ops: map/unmap domain callbacks + * @host_data: Controller private data pointer + */ +struct irq_domain *irq_domain_add_linear(struct device_node *of_node, +					 unsigned int size, +					 const struct irq_domain_ops *ops, +					 void *host_data) +{ +	struct irq_domain *domain; +	unsigned int *revmap; + +	revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL); +	if (WARN_ON(!revmap)) +		return NULL; + +	domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data); +	if (!domain) { +		kfree(revmap); +		return NULL; +	} +	domain->revmap_data.linear.size = size; +	domain->revmap_data.linear.revmap = revmap; +	irq_domain_add(domain); +	return domain; +} + +struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, +					 const struct irq_domain_ops *ops, +					 void *host_data) +{ +	struct irq_domain *domain = irq_domain_alloc(of_node, +					IRQ_DOMAIN_MAP_NOMAP, ops, host_data); +	if (domain) +		irq_domain_add(domain); +	return domain; +} + +/** + * irq_domain_add_tree() + * @of_node: pointer to interrupt controller's device tree node. + * @ops: map/unmap domain callbacks + * + * Note: The radix tree will be allocated later during boot automatically + * (the reverse mapping will use the slow path until that happens). + */ +struct irq_domain *irq_domain_add_tree(struct device_node *of_node, +					 const struct irq_domain_ops *ops, +					 void *host_data) +{ +	struct irq_domain *domain = irq_domain_alloc(of_node, +					IRQ_DOMAIN_MAP_TREE, ops, host_data); +	if (domain) { +		INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL); +		irq_domain_add(domain); +	} +	return domain;  }  /** - * irq_domain_del() - Unregister an irq_domain - * @domain: ptr to registered irq_domain. + * irq_find_host() - Locates a domain for a given device node + * @node: device-tree node of the interrupt controller   */ -void irq_domain_del(struct irq_domain *domain) +struct irq_domain *irq_find_host(struct device_node *node)  { -	struct irq_data *d; -	int hwirq, irq; +	struct irq_domain *h, *found = NULL; +	int rc; +	/* We might want to match the legacy controller last since +	 * it might potentially be set to match all interrupts in +	 * the absence of a device node. This isn't a problem so far +	 * yet though... +	 */  	mutex_lock(&irq_domain_mutex); -	list_del(&domain->list); +	list_for_each_entry(h, &irq_domain_list, link) { +		if (h->ops->match) +			rc = h->ops->match(h, node); +		else +			rc = (h->of_node != NULL) && (h->of_node == node); + +		if (rc) { +			found = h; +			break; +		} +	}  	mutex_unlock(&irq_domain_mutex); +	return found; +} +EXPORT_SYMBOL_GPL(irq_find_host); + +/** + * irq_set_default_host() - Set a "default" irq domain + * @domain: default domain pointer + * + * For convenience, it's possible to set a "default" domain that will be used + * whenever NULL is passed to irq_create_mapping(). It makes life easier for + * platforms that want to manipulate a few hard coded interrupt numbers that + * aren't properly represented in the device-tree. + */ +void irq_set_default_host(struct irq_domain *domain) +{ +	pr_debug("irq: Default domain set to @0x%p\n", domain); + +	irq_default_domain = domain; +} + +/** + * irq_set_virq_count() - Set the maximum number of linux irqs + * @count: number of linux irqs, capped with NR_IRQS + * + * This is mainly for use by platforms like iSeries who want to program + * the virtual irq number in the controller to avoid the reverse mapping + */ +void irq_set_virq_count(unsigned int count) +{ +	pr_debug("irq: Trying to set virq count to %d\n", count); -	/* Clear the irq_domain assignments */ -	irq_domain_for_each_irq(domain, hwirq, irq) { -		d = irq_get_irq_data(irq); -		d->domain = NULL; +	BUG_ON(count < NUM_ISA_INTERRUPTS); +	if (count < NR_IRQS) +		irq_virq_count = count; +} + +static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, +			    irq_hw_number_t hwirq) +{ +	struct irq_data *irq_data = irq_get_irq_data(virq); + +	irq_data->hwirq = hwirq; +	irq_data->domain = domain; +	if (domain->ops->map(domain, virq, hwirq)) { +		pr_debug("irq: -> mapping failed, freeing\n"); +		irq_data->domain = NULL; +		irq_data->hwirq = 0; +		return -1;  	} + +	irq_clear_status_flags(virq, IRQ_NOREQUEST); + +	return 0;  } -#if defined(CONFIG_OF_IRQ)  /** - * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec + * irq_create_direct_mapping() - Allocate an irq for direct mapping + * @domain: domain to allocate the irq for or NULL for default domain   * - * Used by the device tree interrupt mapping code to translate a device tree - * interrupt specifier to a valid linux irq number.  Returns either a valid - * linux IRQ number or 0. + * This routine is used for irq controllers which can choose the hardware + * interrupt numbers they generate. In such a case it's simplest to use + * the linux irq as the hardware interrupt number. + */ +unsigned int irq_create_direct_mapping(struct irq_domain *domain) +{ +	unsigned int virq; + +	if (domain == NULL) +		domain = irq_default_domain; + +	BUG_ON(domain == NULL); +	WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP); + +	virq = irq_alloc_desc_from(1, 0); +	if (!virq) { +		pr_debug("irq: create_direct virq allocation failed\n"); +		return 0; +	} +	if (virq >= irq_virq_count) { +		pr_err("ERROR: no free irqs available below %i maximum\n", +			irq_virq_count); +		irq_free_desc(virq); +		return 0; +	} + +	pr_debug("irq: create_direct obtained virq %d\n", virq); + +	if (irq_setup_virq(domain, virq, virq)) { +		irq_free_desc(virq); +		return 0; +	} + +	return virq; +} + +/** + * irq_create_mapping() - Map a hardware interrupt into linux irq space + * @domain: domain owning this hardware interrupt or NULL for default domain + * @hwirq: hardware irq number in that domain space   * - * When the caller no longer need the irq number returned by this function it - * should arrange to call irq_dispose_mapping(). + * Only one mapping per hardware interrupt is permitted. Returns a linux + * irq number. + * If the sense/trigger is to be specified, set_irq_type() should be called + * on the number returned from that call.   */ +unsigned int irq_create_mapping(struct irq_domain *domain, +				irq_hw_number_t hwirq) +{ +	unsigned int virq, hint; + +	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); + +	/* Look for default domain if nececssary */ +	if (domain == NULL) +		domain = irq_default_domain; +	if (domain == NULL) { +		printk(KERN_WARNING "irq_create_mapping called for" +		       " NULL domain, hwirq=%lx\n", hwirq); +		WARN_ON(1); +		return 0; +	} +	pr_debug("irq: -> using domain @%p\n", domain); + +	/* Check if mapping already exists */ +	virq = irq_find_mapping(domain, hwirq); +	if (virq) { +		pr_debug("irq: -> existing mapping on virq %d\n", virq); +		return virq; +	} + +	/* Get a virtual interrupt number */ +	if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) +		return irq_domain_legacy_revmap(domain, hwirq); + +	/* Allocate a virtual interrupt number */ +	hint = hwirq % irq_virq_count; +	if (hint == 0) +		hint++; +	virq = irq_alloc_desc_from(hint, 0); +	if (!virq) +		virq = irq_alloc_desc_from(1, 0); +	if (!virq) { +		pr_debug("irq: -> virq allocation failed\n"); +		return 0; +	} + +	if (irq_setup_virq(domain, virq, hwirq)) { +		if (domain->revmap_type != IRQ_DOMAIN_MAP_LEGACY) +			irq_free_desc(virq); +		return 0; +	} + +	pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n", +		hwirq, domain->of_node ? domain->of_node->full_name : "null", virq); + +	return virq; +} +EXPORT_SYMBOL_GPL(irq_create_mapping); +  unsigned int irq_create_of_mapping(struct device_node *controller,  				   const u32 *intspec, unsigned int intsize)  {  	struct irq_domain *domain; -	unsigned long hwirq; -	unsigned int irq, type; -	int rc = -EINVAL; +	irq_hw_number_t hwirq; +	unsigned int type = IRQ_TYPE_NONE; +	unsigned int virq; -	/* Find a domain which can translate the irq spec */ -	mutex_lock(&irq_domain_mutex); -	list_for_each_entry(domain, &irq_domain_list, list) { -		if (!domain->ops->dt_translate) -			continue; -		rc = domain->ops->dt_translate(domain, controller, -					intspec, intsize, &hwirq, &type); -		if (rc == 0) -			break; +	domain = controller ? irq_find_host(controller) : irq_default_domain; +	if (!domain) { +#ifdef CONFIG_MIPS +		/* +		 * Workaround to avoid breaking interrupt controller drivers +		 * that don't yet register an irq_domain.  This is temporary +		 * code. ~~~gcl, Feb 24, 2012 +		 * +		 * Scheduled for removal in Linux v3.6.  That should be enough +		 * time. +		 */ +		if (intsize > 0) +			return intspec[0]; +#endif +		printk(KERN_WARNING "irq: no irq domain found for %s !\n", +		       controller->full_name); +		return 0;  	} -	mutex_unlock(&irq_domain_mutex); -	if (rc != 0) -		return 0; +	/* If domain has no translation, then we assume interrupt line */ +	if (domain->ops->xlate == NULL) +		hwirq = intspec[0]; +	else { +		if (domain->ops->xlate(domain, controller, intspec, intsize, +				     &hwirq, &type)) +			return 0; +	} + +	/* Create mapping */ +	virq = irq_create_mapping(domain, hwirq); +	if (!virq) +		return virq; -	irq = irq_domain_to_irq(domain, hwirq); -	if (type != IRQ_TYPE_NONE) -		irq_set_irq_type(irq, type); -	pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n", -		 controller->full_name, (int)hwirq, irq, type); -	return irq; +	/* Set type if specified and different than the current one */ +	if (type != IRQ_TYPE_NONE && +	    type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) +		irq_set_irq_type(virq, type); +	return virq;  }  EXPORT_SYMBOL_GPL(irq_create_of_mapping);  /** - * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping() - * @irq: linux irq number to be discarded + * irq_dispose_mapping() - Unmap an interrupt + * @virq: linux irq number of the interrupt to unmap + */ +void irq_dispose_mapping(unsigned int virq) +{ +	struct irq_data *irq_data = irq_get_irq_data(virq); +	struct irq_domain *domain; +	irq_hw_number_t hwirq; + +	if (!virq || !irq_data) +		return; + +	domain = irq_data->domain; +	if (WARN_ON(domain == NULL)) +		return; + +	/* Never unmap legacy interrupts */ +	if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) +		return; + +	irq_set_status_flags(virq, IRQ_NOREQUEST); + +	/* remove chip and handler */ +	irq_set_chip_and_handler(virq, NULL, NULL); + +	/* Make sure it's completed */ +	synchronize_irq(virq); + +	/* Tell the PIC about it */ +	if (domain->ops->unmap) +		domain->ops->unmap(domain, virq); +	smp_mb(); + +	/* Clear reverse map */ +	hwirq = irq_data->hwirq; +	switch(domain->revmap_type) { +	case IRQ_DOMAIN_MAP_LINEAR: +		if (hwirq < domain->revmap_data.linear.size) +			domain->revmap_data.linear.revmap[hwirq] = 0; +		break; +	case IRQ_DOMAIN_MAP_TREE: +		mutex_lock(&revmap_trees_mutex); +		radix_tree_delete(&domain->revmap_data.tree, hwirq); +		mutex_unlock(&revmap_trees_mutex); +		break; +	} + +	irq_free_desc(virq); +} +EXPORT_SYMBOL_GPL(irq_dispose_mapping); + +/** + * irq_find_mapping() - Find a linux irq from an hw irq number. + * @domain: domain owning this hardware interrupt + * @hwirq: hardware irq number in that domain space + * + * This is a slow path, for use by generic code. It's expected that an + * irq controller implementation directly calls the appropriate low level + * mapping function. + */ +unsigned int irq_find_mapping(struct irq_domain *domain, +			      irq_hw_number_t hwirq) +{ +	unsigned int i; +	unsigned int hint = hwirq % irq_virq_count; + +	/* Look for default domain if nececssary */ +	if (domain == NULL) +		domain = irq_default_domain; +	if (domain == NULL) +		return 0; + +	/* legacy -> bail early */ +	if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) +		return irq_domain_legacy_revmap(domain, hwirq); + +	/* Slow path does a linear search of the map */ +	if (hint == 0) +		hint = 1; +	i = hint; +	do { +		struct irq_data *data = irq_get_irq_data(i); +		if (data && (data->domain == domain) && (data->hwirq == hwirq)) +			return i; +		i++; +		if (i >= irq_virq_count) +			i = 1; +	} while(i != hint); +	return 0; +} +EXPORT_SYMBOL_GPL(irq_find_mapping); + +/** + * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number. + * @domain: domain owning this hardware interrupt + * @hwirq: hardware irq number in that domain space   * - * Calling this function indicates the caller no longer needs a reference to - * the linux irq number returned by a prior call to irq_create_of_mapping(). + * This is a fast path, for use by irq controller code that uses radix tree + * revmaps   */ -void irq_dispose_mapping(unsigned int irq) +unsigned int irq_radix_revmap_lookup(struct irq_domain *domain, +				     irq_hw_number_t hwirq)  { +	struct irq_data *irq_data; + +	if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_TREE)) +		return irq_find_mapping(domain, hwirq); + +	/* +	 * Freeing an irq can delete nodes along the path to +	 * do the lookup via call_rcu. +	 */ +	rcu_read_lock(); +	irq_data = radix_tree_lookup(&domain->revmap_data.tree, hwirq); +	rcu_read_unlock(); +  	/* -	 * nothing yet; will be filled when support for dynamic allocation of -	 * irq_descs is added to irq_domain +	 * If found in radix tree, then fine. +	 * Else fallback to linear lookup - this should not happen in practice +	 * as it means that we failed to insert the node in the radix tree.  	 */ +	return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);  } -EXPORT_SYMBOL_GPL(irq_dispose_mapping); -int irq_domain_simple_dt_translate(struct irq_domain *d, -			    struct device_node *controller, -			    const u32 *intspec, unsigned int intsize, -			    unsigned long *out_hwirq, unsigned int *out_type) +/** + * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping. + * @domain: domain owning this hardware interrupt + * @virq: linux irq number + * @hwirq: hardware irq number in that domain space + * + * This is for use by irq controllers that use a radix tree reverse + * mapping for fast lookup. + */ +void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq, +			     irq_hw_number_t hwirq)  { -	if (d->of_node != controller) -		return -EINVAL; -	if (intsize < 1) -		return -EINVAL; -	if (d->nr_irq && ((intspec[0] < d->hwirq_base) || -	    (intspec[0] >= d->hwirq_base + d->nr_irq))) -		return -EINVAL; +	struct irq_data *irq_data = irq_get_irq_data(virq); + +	if (WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_TREE)) +		return; + +	if (virq) { +		mutex_lock(&revmap_trees_mutex); +		radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data); +		mutex_unlock(&revmap_trees_mutex); +	} +} + +/** + * irq_linear_revmap() - Find a linux irq from a hw irq number. + * @domain: domain owning this hardware interrupt + * @hwirq: hardware irq number in that domain space + * + * This is a fast path, for use by irq controller code that uses linear + * revmaps. It does fallback to the slow path if the revmap doesn't exist + * yet and will create the revmap entry with appropriate locking + */ +unsigned int irq_linear_revmap(struct irq_domain *domain, +			       irq_hw_number_t hwirq) +{ +	unsigned int *revmap; + +	if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) +		return irq_find_mapping(domain, hwirq); + +	/* Check revmap bounds */ +	if (unlikely(hwirq >= domain->revmap_data.linear.size)) +		return irq_find_mapping(domain, hwirq); + +	/* Check if revmap was allocated */ +	revmap = domain->revmap_data.linear.revmap; +	if (unlikely(revmap == NULL)) +		return irq_find_mapping(domain, hwirq); + +	/* Fill up revmap with slow path if no mapping found */ +	if (unlikely(!revmap[hwirq])) +		revmap[hwirq] = irq_find_mapping(domain, hwirq); + +	return revmap[hwirq]; +} + +#ifdef CONFIG_VIRQ_DEBUG +static int virq_debug_show(struct seq_file *m, void *private) +{ +	unsigned long flags; +	struct irq_desc *desc; +	const char *p; +	static const char none[] = "none"; +	void *data; +	int i; + +	seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq", +		      "chip name", "chip data", "domain name"); + +	for (i = 1; i < nr_irqs; i++) { +		desc = irq_to_desc(i); +		if (!desc) +			continue; + +		raw_spin_lock_irqsave(&desc->lock, flags); + +		if (desc->action && desc->action->handler) { +			struct irq_chip *chip; + +			seq_printf(m, "%5d  ", i); +			seq_printf(m, "0x%05lx  ", desc->irq_data.hwirq); + +			chip = irq_desc_get_chip(desc); +			if (chip && chip->name) +				p = chip->name; +			else +				p = none; +			seq_printf(m, "%-15s  ", p); + +			data = irq_desc_get_chip_data(desc); +			seq_printf(m, "0x%16p  ", data); + +			if (desc->irq_data.domain->of_node) +				p = desc->irq_data.domain->of_node->full_name; +			else +				p = none; +			seq_printf(m, "%s\n", p); +		} + +		raw_spin_unlock_irqrestore(&desc->lock, flags); +	} + +	return 0; +} +static int virq_debug_open(struct inode *inode, struct file *file) +{ +	return single_open(file, virq_debug_show, inode->i_private); +} + +static const struct file_operations virq_debug_fops = { +	.open = virq_debug_open, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; + +static int __init irq_debugfs_init(void) +{ +	if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, +				 NULL, &virq_debug_fops) == NULL) +		return -ENOMEM; + +	return 0; +} +__initcall(irq_debugfs_init); +#endif /* CONFIG_VIRQ_DEBUG */ + +int irq_domain_simple_map(struct irq_domain *d, unsigned int irq, +			  irq_hw_number_t hwirq) +{ +	return 0; +} + +/** + * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings + * + * Device Tree IRQ specifier translation function which works with one cell + * bindings where the cell value maps directly to the hwirq number. + */ +int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, +			     const u32 *intspec, unsigned int intsize, +			     unsigned long *out_hwirq, unsigned int *out_type) +{ +	if (WARN_ON(intsize < 1)) +		return -EINVAL;  	*out_hwirq = intspec[0];  	*out_type = IRQ_TYPE_NONE; -	if (intsize > 1) -		*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;  	return 0;  } +EXPORT_SYMBOL_GPL(irq_domain_xlate_onecell);  /** - * irq_domain_create_simple() - Set up a 'simple' translation range + * irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings + * + * Device Tree IRQ specifier translation function which works with two cell + * bindings where the cell values map directly to the hwirq number + * and linux irq flags.   */ -void irq_domain_add_simple(struct device_node *controller, int irq_base) +int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, +			const u32 *intspec, unsigned int intsize, +			irq_hw_number_t *out_hwirq, unsigned int *out_type)  { -	struct irq_domain *domain; - -	domain = kzalloc(sizeof(*domain), GFP_KERNEL); -	if (!domain) { -		WARN_ON(1); -		return; -	} +	if (WARN_ON(intsize < 2)) +		return -EINVAL; +	*out_hwirq = intspec[0]; +	*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; +	return 0; +} +EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell); -	domain->irq_base = irq_base; -	domain->of_node = of_node_get(controller); -	domain->ops = &irq_domain_simple_ops; -	irq_domain_add(domain); +/** + * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings + * + * Device Tree IRQ specifier translation function which works with either one + * or two cell bindings where the cell values map directly to the hwirq number + * and linux irq flags. + * + * Note: don't use this function unless your interrupt controller explicitly + * supports both one and two cell bindings.  For the majority of controllers + * the _onecell() or _twocell() variants above should be used. + */ +int irq_domain_xlate_onetwocell(struct irq_domain *d, +				struct device_node *ctrlr, +				const u32 *intspec, unsigned int intsize, +				unsigned long *out_hwirq, unsigned int *out_type) +{ +	if (WARN_ON(intsize < 1)) +		return -EINVAL; +	*out_hwirq = intspec[0]; +	*out_type = (intsize > 1) ? intspec[1] : IRQ_TYPE_NONE; +	return 0;  } -EXPORT_SYMBOL_GPL(irq_domain_add_simple); +EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell); +const struct irq_domain_ops irq_domain_simple_ops = { +	.map = irq_domain_simple_map, +	.xlate = irq_domain_xlate_onetwocell, +}; +EXPORT_SYMBOL_GPL(irq_domain_simple_ops); + +#ifdef CONFIG_OF_IRQ  void irq_domain_generate_simple(const struct of_device_id *match,  				u64 phys_base, unsigned int irq_start)  {  	struct device_node *node; -	pr_info("looking for phys_base=%llx, irq_start=%i\n", +	pr_debug("looking for phys_base=%llx, irq_start=%i\n",  		(unsigned long long) phys_base, (int) irq_start);  	node = of_find_matching_node_by_address(NULL, match, phys_base);  	if (node) -		irq_domain_add_simple(node, irq_start); -	else -		pr_info("no node found\n"); +		irq_domain_add_legacy(node, 32, irq_start, 0, +				      &irq_domain_simple_ops, NULL);  }  EXPORT_SYMBOL_GPL(irq_domain_generate_simple); -#endif /* CONFIG_OF_IRQ */ - -struct irq_domain_ops irq_domain_simple_ops = { -#ifdef CONFIG_OF_IRQ -	.dt_translate = irq_domain_simple_dt_translate, -#endif /* CONFIG_OF_IRQ */ -}; -EXPORT_SYMBOL_GPL(irq_domain_simple_ops); +#endif  |