From 7ab3a837adfc502913e0101d83bd3f4692b690b6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:47 -0700 Subject: [PATCH 01/33] irq_domain: add documentation and MAINTAINERS entry. Documentation for irq_domain library which will be created in subsequent patches. v4: editorial changes Signed-off-by: Grant Likely Reviewed-by: Randy Dunlap Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Rob Herring Cc: Milton Miller Tested-by: Olof Johansson --- Documentation/IRQ-domain.txt | 117 +++++++++++++++++++++++++++++++++++ MAINTAINERS | 9 +++ 2 files changed, 126 insertions(+) create mode 100644 Documentation/IRQ-domain.txt diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt new file mode 100644 index 000000000000..27dcaabfb4db --- /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 9a648eb8e213..57dd0f56cd37 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 +M: Grant Likely +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 S: Maintained From e1964c50a83d1ce53731c88271d12ac92292a880 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:48 -0700 Subject: [PATCH 02/33] irq_domain: Be less verbose irq_domain printk's too much. Drop some output. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Thomas Gleixner Tested-by: Olof Johansson --- kernel/irq/irqdomain.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 1f9e26526b69..cc2cd43ec740 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -170,13 +170,11 @@ 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"); } EXPORT_SYMBOL_GPL(irq_domain_generate_simple); #endif /* CONFIG_OF_IRQ */ From 7bb69bade0d41715bdf1b24f5ef0b8f798769fe9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:48 -0700 Subject: [PATCH 03/33] irq_domain: Make irq_domain structure match powerpc's irq_host Part of the series to unify the irq remapping mechanisms in the kernel. A follow up patch will copy the powerpc implementation into kernel/irq/irqdomain.c, which will be a lot easier if the structures are identical. Where they differ, I've chose to use the powerpc names since there is a lot more code using those names. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/arm/common/gic.c | 14 +++---- include/linux/irqdomain.h | 84 +++++++++++++++++++++++++++++---------- kernel/irq/irqdomain.c | 14 +++---- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index c47d6199b784..dc19862be0a8 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -619,10 +619,10 @@ 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_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; @@ -641,9 +641,9 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d, } #endif -const struct irq_domain_ops gic_irq_domain_ops = { +struct irq_domain_ops gic_irq_domain_ops = { #ifdef CONFIG_OF - .dt_translate = gic_irq_domain_dt_translate, + .xlate = gic_irq_domain_xlate, #endif }; @@ -721,7 +721,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, irq_start); domain->irq_base = irq_start; } - domain->priv = gic; + domain->host_data = gic; domain->ops = &gic_irq_domain_ops; irq_domain_add(domain); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index bd4272b61a14..35b9ff382e45 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -9,61 +9,105 @@ * 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. */ + #ifndef _LINUX_IRQDOMAIN_H #define _LINUX_IRQDOMAIN_H -#include -#include +#include +#include -#ifdef CONFIG_IRQ_DOMAIN struct device_node; struct irq_domain; +struct of_device_id; + +/* 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 + * @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 * @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. + * @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 { + 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); 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 (*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; + struct list_head link; + + /* type of reverse mapping_technique */ + unsigned int revmap_type; +#define IRQ_DOMAIN_MAP_LEGACY 0 /* 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 */ + union { + struct { + unsigned int size; + unsigned int *revmap; + } linear; + struct radix_tree_root tree; + } revmap_data; + struct irq_domain_ops *ops; + void *host_data; + irq_hw_number_t inval_irq; + unsigned int irq_base; unsigned int nr_irq; unsigned int hwirq_base; - const struct irq_domain_ops *ops; - void *priv; + + /* Optional device node pointer */ struct device_node *of_node; }; +#ifdef CONFIG_IRQ_DOMAIN /** * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number * diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index cc2cd43ec740..509adb8762d7 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -43,7 +43,7 @@ void irq_domain_add(struct irq_domain *domain) } mutex_lock(&irq_domain_mutex); - list_add(&domain->list, &irq_domain_list); + list_add(&domain->link, &irq_domain_list); mutex_unlock(&irq_domain_mutex); } @@ -57,7 +57,7 @@ void irq_domain_del(struct irq_domain *domain) int hwirq, irq; mutex_lock(&irq_domain_mutex); - list_del(&domain->list); + list_del(&domain->link); mutex_unlock(&irq_domain_mutex); /* Clear the irq_domain assignments */ @@ -88,10 +88,10 @@ unsigned int irq_create_of_mapping(struct device_node *controller, /* 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) + list_for_each_entry(domain, &irq_domain_list, link) { + if (!domain->ops->xlate) continue; - rc = domain->ops->dt_translate(domain, controller, + rc = domain->ops->xlate(domain, controller, intspec, intsize, &hwirq, &type); if (rc == 0) break; @@ -126,7 +126,7 @@ void irq_dispose_mapping(unsigned int irq) } EXPORT_SYMBOL_GPL(irq_dispose_mapping); -int irq_domain_simple_dt_translate(struct irq_domain *d, +int irq_domain_simple_xlate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type) @@ -181,7 +181,7 @@ EXPORT_SYMBOL_GPL(irq_domain_generate_simple); struct irq_domain_ops irq_domain_simple_ops = { #ifdef CONFIG_OF_IRQ - .dt_translate = irq_domain_simple_dt_translate, + .xlate = irq_domain_simple_xlate, #endif /* CONFIG_OF_IRQ */ }; EXPORT_SYMBOL_GPL(irq_domain_simple_ops); From 644bd954313254b54e08b69077e16831b6e04dfa Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:49 -0700 Subject: [PATCH 04/33] irq_domain: convert microblaze from irq_host to irq_domain Trivial change, microblaze doesn't use irq remapping yet. Signed-off-by: Grant Likely Cc: Michal Simek Cc: Thomas Gleixner --- arch/microblaze/include/asm/irq.h | 4 ++-- arch/microblaze/kernel/irq.c | 2 +- arch/microblaze/kernel/setup.c | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index a175132e4496..7798ad14c610 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h @@ -39,7 +39,7 @@ static inline void irq_dispose_mapping(unsigned int virq) return; } -struct irq_host; +struct irq_domain; /** * irq_create_mapping - Map a hardware interrupt into linux virq space @@ -51,7 +51,7 @@ struct irq_host; * 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, +extern unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); #endif /* _ASM_MICROBLAZE_IRQ_H */ diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index bbebcae72c02..3f613dfe5a07 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -51,7 +51,7 @@ next_irq: /* 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) +unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq) { return hwirq + IRQ_OFFSET; } diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 604cd9dd1333..70e6d0b41ab4 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(); From bae1d8f19983fbfa25559aa3cb6a81a84aa82a18 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:50 -0700 Subject: [PATCH 05/33] irq_domain/powerpc: Use common irq_domain structure instead of irq_host This patch drops the powerpc-specific irq_host structures and uses the common irq_domain strucutres defined in linux/irqdomain.h. It also fixes all the users to use the new structure names. Renaming irq_host to irq_domain has been discussed for a long time, and this patch is a step in the process of generalizing the powerpc virq code to be usable by all architecture. An astute reader will notice that this patch actually removes the irq_host structure instead of renaming it. This is because the irq_domain structure already exists in include/linux/irqdomain.h and has the needed data members. Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/include/asm/ehv_pic.h | 2 +- arch/powerpc/include/asm/i8259.h | 2 +- arch/powerpc/include/asm/irq.h | 110 ++++-------------- arch/powerpc/include/asm/mpic.h | 2 +- arch/powerpc/include/asm/xics.h | 2 +- arch/powerpc/kernel/irq.c | 78 ++++++------- .../powerpc/platforms/512x/mpc5121_ads_cpld.c | 11 +- arch/powerpc/platforms/52xx/media5200.c | 10 +- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 12 +- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 10 +- arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 10 +- .../platforms/85xx/socrates_fpga_pic.c | 12 +- arch/powerpc/platforms/86xx/gef_pic.c | 12 +- arch/powerpc/platforms/cell/axon_msi.c | 28 ++--- arch/powerpc/platforms/cell/beat_interrupt.c | 14 +-- arch/powerpc/platforms/cell/interrupt.c | 14 +-- arch/powerpc/platforms/cell/spider-pic.c | 10 +- .../platforms/embedded6xx/flipper-pic.c | 30 ++--- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 36 +++--- arch/powerpc/platforms/iseries/irq.c | 12 +- arch/powerpc/platforms/powermac/pic.c | 12 +- arch/powerpc/platforms/powermac/smp.c | 8 +- arch/powerpc/platforms/ps3/interrupt.c | 10 +- arch/powerpc/platforms/wsp/opb_pic.c | 10 +- arch/powerpc/sysdev/cpm1.c | 8 +- arch/powerpc/sysdev/cpm2_pic.c | 10 +- arch/powerpc/sysdev/ehv_pic.c | 10 +- arch/powerpc/sysdev/fsl_msi.c | 6 +- arch/powerpc/sysdev/fsl_msi.h | 2 +- arch/powerpc/sysdev/i8259.c | 14 +-- arch/powerpc/sysdev/ipic.c | 10 +- arch/powerpc/sysdev/ipic.h | 2 +- arch/powerpc/sysdev/mpc8xx_pic.c | 10 +- arch/powerpc/sysdev/mpic.c | 12 +- arch/powerpc/sysdev/mpic_msi.c | 2 +- arch/powerpc/sysdev/mv64x60_pic.c | 8 +- arch/powerpc/sysdev/qe_lib/qe_ic.c | 10 +- arch/powerpc/sysdev/qe_lib/qe_ic.h | 2 +- arch/powerpc/sysdev/tsi108_pci.c | 14 +-- arch/powerpc/sysdev/uic.c | 10 +- arch/powerpc/sysdev/xics/xics-common.c | 12 +- arch/powerpc/sysdev/xilinx_intc.c | 16 +-- drivers/gpio/gpio-mpc8xxx.c | 10 +- 43 files changed, 277 insertions(+), 348 deletions(-) diff --git a/arch/powerpc/include/asm/ehv_pic.h b/arch/powerpc/include/asm/ehv_pic.h index a9e1f4f796f6..dc7d48e3ea90 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 105ade297aad..c3fdfbd5a673 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 c0e1bc319e35..cb06b39f8e61 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 #include #include #include @@ -41,20 +42,7 @@ extern atomic_t ppc_n_lost_interrupts; /* 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 @@ -66,90 +54,32 @@ typedef unsigned long irq_hw_number_t; * 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); +extern bool virq_is_host(unsigned int virq, struct irq_domain *host); /** - * irq_alloc_host - Allocate a new irq_host data structure + * irq_alloc_host - 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 - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map + * @revmap_arg: for IRQ_DOMAIN_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 + * Allocates and initialize and irq_domain structure. Note that in the case of + * IRQ_DOMAIN_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 + * a legacy controller). For a IRQ_DOMAIN_MAP_LINEAR, the map is allocated by + * this call as well. For a IRQ_DOMAIN_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, +extern struct irq_domain *irq_alloc_host(struct device_node *of_node, unsigned int revmap_type, unsigned int revmap_arg, - struct irq_host_ops *ops, + struct irq_domain_ops *ops, irq_hw_number_t inval_irq); @@ -157,7 +87,7 @@ extern struct irq_host *irq_alloc_host(struct device_node *of_node, * 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); +extern struct irq_domain *irq_find_host(struct device_node *node); /** @@ -169,7 +99,7 @@ extern struct irq_host *irq_find_host(struct device_node *node); * 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); +extern void irq_set_default_host(struct irq_domain *host); /** @@ -192,7 +122,7 @@ extern void irq_set_virq_count(unsigned int count); * 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, +extern unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); @@ -211,7 +141,7 @@ extern void irq_dispose_mapping(unsigned int virq); * irq controller implementation directly calls the appropriate low level * mapping function. */ -extern unsigned int irq_find_mapping(struct irq_host *host, +extern unsigned int irq_find_mapping(struct irq_domain *host, irq_hw_number_t hwirq); /** @@ -222,7 +152,7 @@ extern unsigned int irq_find_mapping(struct irq_host *host, * 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); +extern unsigned int irq_create_direct_mapping(struct irq_domain *host); /** * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. @@ -233,7 +163,7 @@ extern unsigned int irq_create_direct_mapping(struct irq_host *host); * 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, +extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, irq_hw_number_t hwirq); /** @@ -244,7 +174,7 @@ extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, * 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, +extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, irq_hw_number_t hwirq); /** @@ -257,7 +187,7 @@ extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, * yet and will create the revmap entry with appropriate locking */ -extern unsigned int irq_linear_revmap(struct irq_host *host, +extern unsigned int irq_linear_revmap(struct irq_domain *host, irq_hw_number_t hwirq); @@ -272,7 +202,7 @@ extern unsigned int irq_linear_revmap(struct irq_host *host, * 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, +extern unsigned int irq_alloc_virt(struct irq_domain *host, unsigned int count, unsigned int hint); diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 67b4d9837236..a5b7c56237f9 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 c48de98ba94e..4ae9a09c3b89 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 701d4aceb4f4..7305f2f65534 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -498,15 +498,15 @@ void do_softirq(void) */ struct irq_map_entry { irq_hw_number_t hwirq; - struct irq_host *host; + struct irq_domain *host; }; -static LIST_HEAD(irq_hosts); +static LIST_HEAD(irq_domain_list); 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; +static struct irq_domain *irq_default_host; irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { @@ -520,31 +520,31 @@ irq_hw_number_t virq_to_hw(unsigned int virq) } EXPORT_SYMBOL_GPL(virq_to_hw); -bool virq_is_host(unsigned int virq, struct irq_host *host) +bool virq_is_host(unsigned int virq, struct irq_domain *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) +static int default_irq_host_match(struct irq_domain *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, +struct irq_domain *irq_alloc_host(struct device_node *of_node, unsigned int revmap_type, unsigned int revmap_arg, - struct irq_host_ops *ops, + struct irq_domain_ops *ops, irq_hw_number_t inval_irq) { - struct irq_host *host; - unsigned int size = sizeof(struct irq_host); + struct irq_domain *host; + unsigned int size = sizeof(struct irq_domain); 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) + if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) size += revmap_arg * sizeof(unsigned int); host = kzalloc(size, GFP_KERNEL); if (host == NULL) @@ -564,7 +564,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, /* 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 (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { if (irq_map[0].host != NULL) { raw_spin_unlock_irqrestore(&irq_big_lock, flags); of_node_put(host->of_node); @@ -574,12 +574,12 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, irq_map[0].host = host; } - list_add(&host->link, &irq_hosts); + list_add(&host->link, &irq_domain_list); raw_spin_unlock_irqrestore(&irq_big_lock, flags); /* Additional setups per revmap type */ switch(revmap_type) { - case IRQ_HOST_MAP_LEGACY: + case IRQ_DOMAIN_MAP_LEGACY: /* 0 is always the invalid number for legacy */ host->inval_irq = 0; /* setup us as the host for all legacy interrupts */ @@ -599,7 +599,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, irq_clear_status_flags(i, IRQ_NOREQUEST); } break; - case IRQ_HOST_MAP_LINEAR: + case IRQ_DOMAIN_MAP_LINEAR: rmap = (unsigned int *)(host + 1); for (i = 0; i < revmap_arg; i++) rmap[i] = NO_IRQ; @@ -607,7 +607,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, smp_wmb(); host->revmap_data.linear.revmap = rmap; break; - case IRQ_HOST_MAP_TREE: + case IRQ_DOMAIN_MAP_TREE: INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); break; default: @@ -619,9 +619,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, return host; } -struct irq_host *irq_find_host(struct device_node *node) +struct irq_domain *irq_find_host(struct device_node *node) { - struct irq_host *h, *found = NULL; + struct irq_domain *h, *found = NULL; unsigned long flags; /* We might want to match the legacy controller last since @@ -630,7 +630,7 @@ struct irq_host *irq_find_host(struct device_node *node) * yet though... */ raw_spin_lock_irqsave(&irq_big_lock, flags); - list_for_each_entry(h, &irq_hosts, link) + list_for_each_entry(h, &irq_domain_list, link) if (h->ops->match(h, node)) { found = h; break; @@ -640,7 +640,7 @@ struct irq_host *irq_find_host(struct device_node *node) } EXPORT_SYMBOL_GPL(irq_find_host); -void irq_set_default_host(struct irq_host *host) +void irq_set_default_host(struct irq_domain *host) { pr_debug("irq: Default host set to @0x%p\n", host); @@ -656,7 +656,7 @@ void irq_set_virq_count(unsigned int count) irq_virq_count = count; } -static int irq_setup_virq(struct irq_host *host, unsigned int virq, +static int irq_setup_virq(struct irq_domain *host, unsigned int virq, irq_hw_number_t hwirq) { int res; @@ -688,7 +688,7 @@ error: return -1; } -unsigned int irq_create_direct_mapping(struct irq_host *host) +unsigned int irq_create_direct_mapping(struct irq_domain *host) { unsigned int virq; @@ -696,7 +696,7 @@ unsigned int irq_create_direct_mapping(struct irq_host *host) host = irq_default_host; BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); + WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); virq = irq_alloc_virt(host, 1, 0); if (virq == NO_IRQ) { @@ -712,7 +712,7 @@ unsigned int irq_create_direct_mapping(struct irq_host *host) return virq; } -unsigned int irq_create_mapping(struct irq_host *host, +unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq) { unsigned int virq, hint; @@ -738,7 +738,7 @@ unsigned int irq_create_mapping(struct irq_host *host, } /* Get a virtual interrupt number */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) { + if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) { /* Handle legacy */ virq = (unsigned int)hwirq; if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) @@ -767,7 +767,7 @@ 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; + struct irq_domain *host; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; unsigned int virq; @@ -806,7 +806,7 @@ EXPORT_SYMBOL_GPL(irq_create_of_mapping); void irq_dispose_mapping(unsigned int virq) { - struct irq_host *host; + struct irq_domain *host; irq_hw_number_t hwirq; if (virq == NO_IRQ) @@ -817,7 +817,7 @@ void irq_dispose_mapping(unsigned int virq) return; /* Never unmap legacy interrupts */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) + if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) return; irq_set_status_flags(virq, IRQ_NOREQUEST); @@ -836,11 +836,11 @@ void irq_dispose_mapping(unsigned int virq) /* Clear reverse map */ hwirq = irq_map[virq].hwirq; switch(host->revmap_type) { - case IRQ_HOST_MAP_LINEAR: + case IRQ_DOMAIN_MAP_LINEAR: if (hwirq < host->revmap_data.linear.size) host->revmap_data.linear.revmap[hwirq] = NO_IRQ; break; - case IRQ_HOST_MAP_TREE: + case IRQ_DOMAIN_MAP_TREE: mutex_lock(&revmap_trees_mutex); radix_tree_delete(&host->revmap_data.tree, hwirq); mutex_unlock(&revmap_trees_mutex); @@ -857,7 +857,7 @@ void irq_dispose_mapping(unsigned int virq) } EXPORT_SYMBOL_GPL(irq_dispose_mapping); -unsigned int irq_find_mapping(struct irq_host *host, +unsigned int irq_find_mapping(struct irq_domain *host, irq_hw_number_t hwirq) { unsigned int i; @@ -870,7 +870,7 @@ unsigned int irq_find_mapping(struct irq_host *host, return NO_IRQ; /* legacy -> bail early */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) + if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) return hwirq; /* Slow path does a linear search of the map */ @@ -925,13 +925,13 @@ int irq_choose_cpu(const struct cpumask *mask) } #endif -unsigned int irq_radix_revmap_lookup(struct irq_host *host, +unsigned int irq_radix_revmap_lookup(struct irq_domain *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)) + if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) return irq_find_mapping(host, hwirq); /* @@ -956,10 +956,10 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host, return virq; } -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, +void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, irq_hw_number_t hwirq) { - if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) + if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) return; if (virq != NO_IRQ) { @@ -970,12 +970,12 @@ void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, } } -unsigned int irq_linear_revmap(struct irq_host *host, +unsigned int irq_linear_revmap(struct irq_domain *host, irq_hw_number_t hwirq) { unsigned int *revmap; - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) + if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) return irq_find_mapping(host, hwirq); /* Check revmap bounds */ @@ -994,7 +994,7 @@ unsigned int irq_linear_revmap(struct irq_host *host, return revmap[hwirq]; } -unsigned int irq_alloc_virt(struct irq_host *host, +unsigned int irq_alloc_virt(struct irq_domain *host, unsigned int count, unsigned int hint) { @@ -1064,7 +1064,7 @@ void irq_free_virt(unsigned int virq, unsigned int count) raw_spin_lock_irqsave(&irq_big_lock, flags); for (i = virq; i < (virq + count); i++) { - struct irq_host *host; + struct irq_domain *host; host = irq_map[i].host; irq_map[i].hwirq = host->inval_irq; diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 9f09319352c0..fefa7977fa9f 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -21,7 +21,7 @@ #include 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 struct irq_domain_ops cpld_pic_host_ops = { .match = cpld_pic_host_match, .map = cpld_pic_host_map, }; @@ -192,7 +191,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); + irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); 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 96f85e5e0cd3..a746415c4242 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 struct irq_domain_ops media5200_irq_ops = { .map = media5200_irq_map, .xlate = media5200_irq_xlate, }; @@ -173,7 +173,7 @@ 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_irq.irqhost = irq_alloc_host(fpga_np, IRQ_DOMAIN_MAP_LINEAR, MEDIA5200_NUM_IRQS, &media5200_irq_ops, -1); if (!media5200_irq.irqhost) diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index f94f06e52762..e90af8fd8413 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 struct irq_domain_ops mpc52xx_gpt_irq_ops = { .map = mpc52xx_gpt_irq_map, .xlate = mpc52xx_gpt_irq_xlate, }; @@ -252,7 +252,7 @@ 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, + gpt->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR, 1, &mpc52xx_gpt_irq_ops, -1); if (!gpt->irqhost) { dev_err(gpt->dev, "irq_alloc_host() failed\n"); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1a9a49570579..8c997f1a9122 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 struct irq_domain_ops mpc52xx_irqhost_ops = { .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; @@ -444,7 +444,7 @@ 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_alloc_host(picnode, IRQ_DOMAIN_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, &mpc52xx_irqhost_ops, -1); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 8ccf9ed62fe2..bdba174e7b3a 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 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,7 +156,7 @@ 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, + host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, NUM_IRQS, &pci_pic_host_ops, NUM_IRQS); if (!host) { ret = -ENOMEM; diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 12cb9bb2cc68..e3ef7c9ed7b1 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 struct irq_domain_ops socrates_fpga_pic_host_ops = { .map = socrates_fpga_pic_host_map, .xlate = socrates_fpga_pic_host_xlate, }; @@ -279,8 +279,8 @@ 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, + /* Setup an irq_domain structure */ + socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_DOMAIN_MAP_LINEAR, SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, SOCRATES_FPGA_NUM_IRQS); if (socrates_fpga_pic_irq_host == NULL) { diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 94594e58594c..0cf8af230bcf 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 struct irq_domain_ops gef_pic_host_ops = { .map = gef_pic_host_map, .xlate = gef_pic_host_xlate, }; @@ -211,8 +211,8 @@ 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, + /* Setup an irq_domain structure */ + gef_pic_irq_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, GEF_PIC_NUM_IRQS, &gef_pic_host_ops, NO_IRQ); if (gef_pic_irq_host == NULL) diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 40a6e34793b4..1bfd18a48a7f 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 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,15 +392,15 @@ 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, + msic->irq_domain = irq_alloc_host(dn, IRQ_DOMAIN_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", + 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; + msic->irq_domain->host_data = msic; irq_set_handler_data(virq, msic); irq_set_chained_handler(virq, axon_msi_cascade); diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 55015e1f6939..21b64cfef5e5 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 struct irq_domain_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, @@ -239,7 +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_host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0, &beatic_pic_host_ops, 0); BUG_ON(beatic_host == NULL); diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 96a433dd2d64..6888475e7c62 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 struct irq_domain_ops iic_host_ops = { .match = iic_host_match, .map = iic_host_map, .xlate = iic_host_xlate, @@ -378,7 +378,7 @@ 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 = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_LINEAR, IIC_SOURCE_COUNT, &iic_host_ops, IIC_IRQ_INVALID); 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 442c28c00f88..1f935a772ef8 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 struct irq_domain_ops spider_host_ops = { .map = spider_host_map, .xlate = spider_host_xlate, }; @@ -299,7 +299,7 @@ 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, + pic->host = irq_alloc_host(of_node, IRQ_DOMAIN_MAP_LINEAR, SPIDER_SRC_COUNT, &spider_host_ops, SPIDER_IRQ_INVALID); if (pic->host == NULL) diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index f61a2dd96b99..f862361730fb 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 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,22 +159,22 @@ 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_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, FLIPPER_NR_IRQS, + &flipper_irq_domain_ops, -1); + if (!irq_domain) { + pr_err("failed to allocate irq_domain\n"); return NULL; } - irq_host->host_data = io_base; + irq_domain->host_data = io_base; out: - return irq_host; + return irq_domain; } unsigned int flipper_pic_get_irq(void) { - void __iomem *io_base = flipper_irq_host->host_data; + void __iomem *io_base = flipper_irq_domain->host_data; int irq; u32 irq_status; @@ -184,7 +184,7 @@ unsigned int flipper_pic_get_irq(void) return NO_IRQ; /* no more IRQs pending */ irq = __ffs(irq_status); - return irq_linear_revmap(flipper_irq_host, irq); + return irq_linear_revmap(flipper_irq_domain, irq); } /* @@ -199,7 +199,7 @@ void __init flipper_pic_probe(void) np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-pic"); BUG_ON(!np); - flipper_irq_host = flipper_pic_init(np); + flipper_irq_domain = flipper_pic_init(np); BUG_ON(!flipper_irq_host); irq_set_default_host(flipper_irq_host); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index e4919170c6bc..2d4a5d48fbbd 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 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,20 +177,20 @@ 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_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, HLWD_NR_IRQS, + &hlwd_irq_domain_ops, -1); + if (!irq_domain) { + pr_err("failed to allocate irq_domain\n"); return NULL; } - irq_host->host_data = io_base; + irq_domain->host_data = io_base; - return irq_host; + return irq_domain; } unsigned int hlwd_pic_get_irq(void) { - return __hlwd_pic_get_irq(hlwd_irq_host); + return __hlwd_pic_get_irq(hlwd_irq_domain); } /* @@ -200,7 +200,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; @@ -214,7 +214,7 @@ void hlwd_pic_probe(void) irq_set_handler_data(cascade_virq, host); irq_set_chained_handler(cascade_virq, hlwd_pic_irq_cascade); - hlwd_irq_host = host; + hlwd_irq_domain = host; break; } } @@ -228,7 +228,7 @@ void hlwd_pic_probe(void) */ void hlwd_quiesce(void) { - void __iomem *io_base = hlwd_irq_host->host_data; + void __iomem *io_base = hlwd_irq_domain->host_data; __hlwd_quiesce(io_base); } diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index b2103453eb01..b07d4f2e0155 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 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,8 @@ 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_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0, + &iseries_irq_domain_ops, 0); 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 7761aabfc293..cff326ab8ef2 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,7 +288,7 @@ 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, +static int pmac_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) @@ -299,7 +299,7 @@ static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops pmac_pic_host_ops = { +static struct irq_domain_ops pmac_pic_host_ops = { .match = pmac_pic_host_match, .map = pmac_pic_host_map, .xlate = pmac_pic_host_xlate, @@ -352,7 +352,7 @@ 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 = irq_alloc_host(master, IRQ_DOMAIN_MAP_LINEAR, max_irqs, &pmac_pic_host_ops, max_irqs); BUG_ON(pmac_pic_host == NULL); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 44d769258ebf..6b1ef2d4dea0 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 = { +struct irq_domain_ops psurge_host_ops = { .map = psurge_host_map, }; @@ -192,7 +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 = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0, &psurge_host_ops, 0); if (psurge_host) diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 617efa12a3a5..c5980e422dc6 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 struct irq_domain_ops ps3_host_ops = { .map = ps3_host_map, .match = ps3_host_match, }; @@ -751,9 +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, + host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0, &ps3_host_ops, PS3_INVALID_OUTLET); 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 19f353dfcd03..76b33bc36116 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,7 +196,7 @@ 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, +static int opb_host_xlate(struct irq_domain *host, struct device_node *dn, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { @@ -207,7 +207,7 @@ static int opb_host_xlate(struct irq_host *host, struct device_node *dn, return 0; } -static struct irq_host_ops opb_host_ops = { +static struct irq_domain_ops opb_host_ops = { .map = opb_host_map, .xlate = opb_host_xlate, }; @@ -267,7 +267,7 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn) * 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->host = irq_alloc_host(dn, IRQ_DOMAIN_MAP_LINEAR, OPB_NR_IRQS, &opb_host_ops, -1); if (!opb->host) { diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 5d7d59a43c4c..0877a757c209 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 struct irq_domain_ops cpm_pic_host_ops = { .map = cpm_pic_host_map, }; @@ -164,7 +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, + cpm_pic_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, 64, &cpm_pic_host_ops, 64); if (cpm_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index bcab50e2a9eb..b149baae5d33 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,7 +224,7 @@ 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, +static int cpm2_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) { @@ -236,7 +236,7 @@ static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops cpm2_pic_host_ops = { +static struct irq_domain_ops cpm2_pic_host_ops = { .map = cpm2_pic_host_map, .xlate = cpm2_pic_host_xlate, }; @@ -275,7 +275,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, + cpm2_pic_host = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64); if (cpm2_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index b6731e4a6646..48d3ba1220d3 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 struct irq_domain_ops ehv_pic_host_ops = { .match = ehv_pic_host_match, .map = ehv_pic_host_map, .xlate = ehv_pic_host_xlate, @@ -275,7 +275,7 @@ void __init ehv_pic_init(void) return; } - ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, + ehv_pic->irqhost = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0); if (!ehv_pic->irqhost) { diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index ecb5c1946d22..3f9a301c4550 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 struct irq_domain_ops fsl_msi_host_ops = { .map = fsl_msi_host_map, }; @@ -387,7 +387,7 @@ 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, + msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_DOMAIN_MAP_LINEAR, NR_MSI_IRQS, &fsl_msi_host_ops, 0); if (msi->irqhost == NULL) { diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index f6c646a52541..8225f8653f78 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 d18bb27e4df9..7e67890b8fc2 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,7 +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, + i8259_host = irq_alloc_host(node, IRQ_DOMAIN_MAP_LEGACY, 0, &i8259_host_ops, 0); if (i8259_host == NULL) { printk(KERN_ERR "i8259: failed to allocate irq host !\n"); diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 95da897f05a7..9abed3760545 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,7 +692,7 @@ 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, +static int ipic_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) @@ -708,7 +708,7 @@ static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, 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, @@ -728,7 +728,7 @@ 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, + ipic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR, NR_IPIC_INTS, &ipic_host_ops, 0); if (ipic->irqhost == NULL) { diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h index 9391c57b0c51..90031d1282e1 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 2ca0a85fcce9..978dfc4c3120 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,7 +171,7 @@ int mpc8xx_pic_init(void) goto out; } - mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, + mpc8xx_pic_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64); if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4e9ccb1015de..c844d343bf32 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,7 +1345,7 @@ 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_alloc_host(mpic->node, IRQ_DOMAIN_MAP_LINEAR, isu_size ? isu_size : mpic->num_sources, &mpic_host_ops, flags & MPIC_LARGE_VECTORS ? 2048 : 256); diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 0f67cd79d481..00395f40fb5d 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; + 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 14d130268e7a..45124a1959d0 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,7 +250,7 @@ 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_irq_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, MV64x60_NUM_IRQS, &mv64x60_host_ops, MV64x60_NUM_IRQS); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 73034bd203c4..78e90192c343 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,7 +272,7 @@ 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, +static int qe_ic_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 qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, 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, @@ -339,7 +339,7 @@ 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, + qe_ic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR, NR_QE_IC_INTS, &qe_ic_host_ops, 0); if (qe_ic->irqhost == NULL) { kfree(qe_ic); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h index c1361d005a8a..c327872ed35c 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 4d18658116e5..f3757236e666 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,10 @@ 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_alloc_host(node, IRQ_DOMAIN_MAP_LEGACY, + 0, &pci_irq_domain_ops, 0); 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 063c901b1265..7eea3a64bdf7 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,7 +190,7 @@ 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, +static int uic_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_type) @@ -202,7 +202,7 @@ static int uic_host_xlate(struct irq_host *h, struct device_node *ct, 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, }; @@ -270,7 +270,7 @@ static struct uic * __init uic_init_one(struct device_node *node) } uic->dcrbase = *dcrreg; - uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, + uic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR, NR_UIC_INTS, &uic_host_ops, -1); if (! uic->irqhost) return NULL; /* FIXME: panic? */ diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index d72eda6a4c05..c4b3ce17029a 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); @@ -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,7 +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_host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_TREE, 0, &xics_host_ops, XICS_IRQ_SPURIOUS); 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 6183799754af..92e7d4db9fde 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,8 +200,8 @@ 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, + /* Allocate and initialize an irq_domain structure. */ + irq = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, XILINX_INTC_MAXIRQS, &xilinx_intc_ops, -1); if (!irq) panic(__FILE__ ": Cannot allocate IRQ host\n"); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 5cd04b65c556..9efd59732eeb 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,7 +296,7 @@ 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, +static int mpc8xxx_gpio_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) @@ -311,7 +311,7 @@ static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, 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, }; @@ -365,7 +365,7 @@ static void __init mpc8xxx_add_controller(struct device_node *np) goto skip_irq; mpc8xxx_gc->irq = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, + irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, MPC8XXX_GPIO_PINS, &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); if (!mpc8xxx_gc->irq) goto skip_irq; From 4bbdd45afdae208a7c4ade89cf602f89a6397cff Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:51 -0700 Subject: [PATCH 06/33] irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead This patch drops the powerpc-specific irq_map table and replaces it with directly using the irq_alloc_desc()/irq_free_desc() interfaces for allocating and freeing irq_desc structures. This patch is a preparation step for generalizing the powerpc-specific virq infrastructure to become irq_domains. As part of this change, the irq_big_lock is changed to a mutex from a raw spinlock. There is no longer any need to use a spin lock since the irq_desc allocation code is now responsible for the critical section of finding an unused range of irq numbers. The radix lookup table is also changed to store the irq_data pointer instead of the irq_map entry since the irq_map is removed. This should end up being functionally equivalent since only allocated irq_descs are ever added to the radix tree. v5: - Really don't ever allocate virq 0. The previous version could still do it if hint == 0 - Respect irq_virq_count setting for NOMAP. Some NOMAP domains cannot use virq values above irq_virq_count. - Use numa_node_id() when allocating irq_descs. Ideally the API should obtain that value from the caller, but that touches a lot of call sites so will be deferred to a follow-on patch. - Fix irq_find_mapping() to include irq numbers lower than NUM_ISA_INTERRUPTS. With the switch to irq_alloc_desc*(), the lowest possible allocated irq is now returned by arch_probe_nr_irqs(). v4: - Fix incorrect access to irq_data structure in debugfs code - Don't ever allocate virq 0 Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/include/asm/irq.h | 27 ---- arch/powerpc/kernel/irq.c | 240 ++++++++++----------------------- 2 files changed, 69 insertions(+), 198 deletions(-) diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index cb06b39f8e61..abdd7ef28cbf 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -191,33 +191,6 @@ extern unsigned int irq_linear_revmap(struct irq_domain *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_domain *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/kernel/irq.c b/arch/powerpc/kernel/irq.c index 7305f2f65534..03c95f03d792 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -491,38 +491,29 @@ void do_softirq(void) * 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_domain *host; -}; - static LIST_HEAD(irq_domain_list); -static DEFINE_RAW_SPINLOCK(irq_big_lock); +static DEFINE_MUTEX(irq_domain_mutex); 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_domain *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_domain *host) { - return irq_map[virq].host == host; + struct irq_data *irq_data = irq_get_irq_data(virq); + return irq_data ? irq_data->domain == host : false; } EXPORT_SYMBOL_GPL(virq_is_host); @@ -537,11 +528,10 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, struct irq_domain_ops *ops, irq_hw_number_t inval_irq) { - struct irq_domain *host; + struct irq_domain *host, *h; unsigned int size = sizeof(struct irq_domain); unsigned int i; unsigned int *rmap; - unsigned long flags; /* Allocate structure and revmap table if using linear mapping */ if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) @@ -559,23 +549,20 @@ struct irq_domain *irq_alloc_host(struct device_node *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 - */ + mutex_lock(&irq_domain_mutex); + /* Make sure only one legacy controller can be created */ if (revmap_type == IRQ_DOMAIN_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; + list_for_each_entry(h, &irq_domain_list, link) { + if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { + mutex_unlock(&irq_domain_mutex); + of_node_put(host->of_node); + kfree(host); + return NULL; + } } - irq_map[0].host = host; } - list_add(&host->link, &irq_domain_list); - raw_spin_unlock_irqrestore(&irq_big_lock, flags); + mutex_unlock(&irq_domain_mutex); /* Additional setups per revmap type */ switch(revmap_type) { @@ -584,10 +571,9 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, 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(); + struct irq_data *irq_data = irq_get_irq_data(i); + irq_data->hwirq = i; + irq_data->domain = host; /* Legacy flags are left to default at this point, * one can then use irq_create_mapping() to @@ -604,7 +590,6 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, 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_DOMAIN_MAP_TREE: @@ -622,20 +607,19 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, struct irq_domain *irq_find_host(struct device_node *node) { struct irq_domain *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); + mutex_lock(&irq_domain_mutex); list_for_each_entry(h, &irq_domain_list, link) if (h->ops->match(h, node)) { found = h; break; } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); + mutex_unlock(&irq_domain_mutex); return found; } EXPORT_SYMBOL_GPL(irq_find_host); @@ -659,33 +643,20 @@ void irq_set_virq_count(unsigned int count) static int irq_setup_virq(struct irq_domain *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(); + struct irq_data *irq_data = irq_get_irq_data(virq); + irq_data->hwirq = hwirq; + irq_data->domain = host; if (host->ops->map(host, virq, hwirq)) { pr_debug("irq: -> mapping failed, freeing\n"); - goto errdesc; + irq_data->domain = NULL; + irq_data->hwirq = 0; + return -1; } 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_domain *host) @@ -698,16 +669,24 @@ unsigned int irq_create_direct_mapping(struct irq_domain *host) BUG_ON(host == NULL); WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); - virq = irq_alloc_virt(host, 1, 0); + virq = irq_alloc_desc_from(1, 0); if (virq == NO_IRQ) { pr_debug("irq: create_direct virq allocation failed\n"); return NO_IRQ; } + 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(host, virq, virq)) + if (irq_setup_virq(host, virq, virq)) { + irq_free_desc(virq); return NO_IRQ; + } return virq; } @@ -747,15 +726,22 @@ unsigned int irq_create_mapping(struct irq_domain *host, } else { /* Allocate a virtual interrupt number */ hint = hwirq % irq_virq_count; - virq = irq_alloc_virt(host, 1, hint); + if (hint == 0) + hint = 1; + virq = irq_alloc_desc_from(hint, 0); + if (!virq) + virq = irq_alloc_desc_from(1, 0); if (virq == NO_IRQ) { pr_debug("irq: -> virq allocation failed\n"); return NO_IRQ; } } - if (irq_setup_virq(host, virq, hwirq)) + if (irq_setup_virq(host, virq, hwirq)) { + if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) + irq_free_desc(virq); 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); @@ -806,13 +792,14 @@ EXPORT_SYMBOL_GPL(irq_create_of_mapping); void irq_dispose_mapping(unsigned int virq) { + struct irq_data *irq_data = irq_get_irq_data(virq); struct irq_domain *host; irq_hw_number_t hwirq; - if (virq == NO_IRQ) + if (virq == NO_IRQ || !irq_data) return; - host = irq_map[virq].host; + host = irq_data->domain; if (WARN_ON(host == NULL)) return; @@ -834,7 +821,7 @@ void irq_dispose_mapping(unsigned int virq) smp_mb(); /* Clear reverse map */ - hwirq = irq_map[virq].hwirq; + hwirq = irq_data->hwirq; switch(host->revmap_type) { case IRQ_DOMAIN_MAP_LINEAR: if (hwirq < host->revmap_data.linear.size) @@ -848,12 +835,9 @@ void irq_dispose_mapping(unsigned int virq) } /* Destroy map */ - smp_mb(); - irq_map[virq].hwirq = host->inval_irq; + irq_data->hwirq = host->inval_irq; - irq_free_descs(virq, 1); - /* Free it */ - irq_free_virt(virq, 1); + irq_free_desc(virq); } EXPORT_SYMBOL_GPL(irq_dispose_mapping); @@ -874,16 +858,16 @@ unsigned int irq_find_mapping(struct irq_domain *host, return hwirq; /* Slow path does a linear search of the map */ - if (hint < NUM_ISA_INTERRUPTS) - hint = NUM_ISA_INTERRUPTS; + if (hint == 0) + hint = 1; i = hint; - do { - if (irq_map[i].host == host && - irq_map[i].hwirq == hwirq) + do { + struct irq_data *data = irq_get_irq_data(i); + if (data && (data->domain == host) && (data->hwirq == hwirq)) return i; i++; if (i >= irq_virq_count) - i = NUM_ISA_INTERRUPTS; + i = 1; } while(i != hint); return NO_IRQ; } @@ -928,19 +912,17 @@ int irq_choose_cpu(const struct cpumask *mask) unsigned int irq_radix_revmap_lookup(struct irq_domain *host, irq_hw_number_t hwirq) { - struct irq_map_entry *ptr; - unsigned int virq; + struct irq_data *irq_data; if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_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 + * 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); + irq_data = radix_tree_lookup(&host->revmap_data.tree, hwirq); rcu_read_unlock(); /* @@ -948,24 +930,20 @@ unsigned int irq_radix_revmap_lookup(struct irq_domain *host, * 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; + return irq_data ? irq_data->irq : irq_find_mapping(host, hwirq); } void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, irq_hw_number_t hwirq) { + struct irq_data *irq_data = irq_get_irq_data(virq); + if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) return; if (virq != NO_IRQ) { mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, - &irq_map[virq]); + radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); mutex_unlock(&revmap_trees_mutex); } } @@ -994,86 +972,6 @@ unsigned int irq_linear_revmap(struct irq_domain *host, return revmap[hwirq]; } -unsigned int irq_alloc_virt(struct irq_domain *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_domain *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; @@ -1103,7 +1001,7 @@ static int virq_debug_show(struct seq_file *m, void *private) struct irq_chip *chip; seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", irq_map[i].hwirq); + seq_printf(m, "0x%05lx ", desc->irq_data.hwirq); chip = irq_desc_get_chip(desc); if (chip && chip->name) @@ -1115,8 +1013,8 @@ static int virq_debug_show(struct seq_file *m, void *private) 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; + 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); From 6d9285b00f776eebe459a858ebf07b56c36c60d2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:51 -0700 Subject: [PATCH 07/33] irq_domain/powerpc: Eliminate virq_is_host() There is only one user, and it is trivial to open-code. Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/include/asm/irq.h | 1 - arch/powerpc/kernel/irq.c | 7 ------- arch/powerpc/sysdev/xics/xics-common.c | 12 ++++++------ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index abdd7ef28cbf..f80f262e0597 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -58,7 +58,6 @@ extern atomic_t ppc_n_lost_interrupts; 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_domain *host); /** * irq_alloc_host - Allocate a new irq_domain data structure diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 03c95f03d792..269fbd5ac62f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -510,13 +510,6 @@ irq_hw_number_t virq_to_hw(unsigned int virq) } EXPORT_SYMBOL_GPL(virq_to_hw); -bool virq_is_host(unsigned int virq, struct irq_domain *host) -{ - struct irq_data *irq_data = irq_get_irq_data(virq); - return irq_data ? irq_data->domain == host : false; -} -EXPORT_SYMBOL_GPL(virq_is_host); - static int default_irq_host_match(struct irq_domain *h, struct device_node *np) { return h->of_node != NULL && h->of_node == np; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index c4b3ce17029a..fb2e303d25fb 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -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; From cc79ca691c292e9fd44f589c7940b9654e22f2f6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 16 Feb 2012 01:37:49 -0700 Subject: [PATCH 08/33] irq_domain: Move irq_domain code from powerpc to kernel/irq This patch only moves the code. It doesn't make any changes, and the code is still only compiled for powerpc. Follow-on patches will generalize the code for other architectures. Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/irq.h | 144 -------- arch/powerpc/kernel/irq.c | 502 --------------------------- include/linux/irqdomain.h | 46 ++- kernel/irq/irqdomain.c | 600 +++++++++++++++++++++++++++++++++ 5 files changed, 643 insertions(+), 650 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1919634a9b32..303703d716fe 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/irq.h b/arch/powerpc/include/asm/irq.h index f80f262e0597..728cc30d04ea 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -42,154 +42,10 @@ extern atomic_t ppc_n_lost_interrupts; /* Same thing, used by the generic IRQ code */ #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS -/* - * 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_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); -/** - * irq_alloc_host - 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 - * @revmap_arg: for IRQ_DOMAIN_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_domain structure. Note that in the case of - * IRQ_DOMAIN_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_DOMAIN_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_DOMAIN_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_domain *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_domain_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_domain *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_domain *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_domain *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_domain *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_domain *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_domain *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_domain *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_domain *host, - irq_hw_number_t hwirq); - - /** * irq_early_init - Init irq remapping subsystem */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 269fbd5ac62f..e3673ff6b7a0 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -486,17 +486,6 @@ void do_softirq(void) local_irq_restore(flags); } - -/* - * IRQ controller and virtual interrupts - */ - -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_host; - irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { return d->hwirq; @@ -510,362 +499,6 @@ irq_hw_number_t virq_to_hw(unsigned int virq) } EXPORT_SYMBOL_GPL(virq_to_hw); -static int default_irq_host_match(struct irq_domain *h, struct device_node *np) -{ - return h->of_node != NULL && h->of_node == np; -} - -struct irq_domain *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_domain_ops *ops, - irq_hw_number_t inval_irq) -{ - struct irq_domain *host, *h; - unsigned int size = sizeof(struct irq_domain); - unsigned int i; - unsigned int *rmap; - - /* Allocate structure and revmap table if using linear mapping */ - if (revmap_type == IRQ_DOMAIN_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; - - mutex_lock(&irq_domain_mutex); - /* Make sure only one legacy controller can be created */ - if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { - list_for_each_entry(h, &irq_domain_list, link) { - if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { - mutex_unlock(&irq_domain_mutex); - of_node_put(host->of_node); - kfree(host); - return NULL; - } - } - } - list_add(&host->link, &irq_domain_list); - mutex_unlock(&irq_domain_mutex); - - /* Additional setups per revmap type */ - switch(revmap_type) { - case IRQ_DOMAIN_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++) { - struct irq_data *irq_data = irq_get_irq_data(i); - irq_data->hwirq = i; - irq_data->domain = host; - - /* 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_DOMAIN_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; - host->revmap_data.linear.revmap = rmap; - break; - case IRQ_DOMAIN_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_domain *irq_find_host(struct device_node *node) -{ - struct irq_domain *h, *found = NULL; - - /* 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_for_each_entry(h, &irq_domain_list, link) - if (h->ops->match(h, node)) { - found = h; - break; - } - mutex_unlock(&irq_domain_mutex); - return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_domain *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_domain *host, 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 = host; - if (host->ops->map(host, 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; -} - -unsigned int irq_create_direct_mapping(struct irq_domain *host) -{ - unsigned int virq; - - if (host == NULL) - host = irq_default_host; - - BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); - - virq = irq_alloc_desc_from(1, 0); - if (virq == NO_IRQ) { - pr_debug("irq: create_direct virq allocation failed\n"); - return NO_IRQ; - } - 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(host, virq, virq)) { - irq_free_desc(virq); - return NO_IRQ; - } - - return virq; -} - -unsigned int irq_create_mapping(struct irq_domain *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_DOMAIN_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; - if (hint == 0) - hint = 1; - virq = irq_alloc_desc_from(hint, 0); - if (!virq) - virq = irq_alloc_desc_from(1, 0); - if (virq == NO_IRQ) { - pr_debug("irq: -> virq allocation failed\n"); - return NO_IRQ; - } - } - - if (irq_setup_virq(host, virq, hwirq)) { - if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) - irq_free_desc(virq); - 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_domain *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_data *irq_data = irq_get_irq_data(virq); - struct irq_domain *host; - irq_hw_number_t hwirq; - - if (virq == NO_IRQ || !irq_data) - return; - - host = irq_data->domain; - if (WARN_ON(host == NULL)) - return; - - /* Never unmap legacy interrupts */ - if (host->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 (host->ops->unmap) - host->ops->unmap(host, virq); - smp_mb(); - - /* Clear reverse map */ - hwirq = irq_data->hwirq; - switch(host->revmap_type) { - case IRQ_DOMAIN_MAP_LINEAR: - if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; - break; - case IRQ_DOMAIN_MAP_TREE: - mutex_lock(&revmap_trees_mutex); - radix_tree_delete(&host->revmap_data.tree, hwirq); - mutex_unlock(&revmap_trees_mutex); - break; - } - - /* Destroy map */ - irq_data->hwirq = host->inval_irq; - - irq_free_desc(virq); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_domain *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_DOMAIN_MAP_LEGACY) - return 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 == host) && (data->hwirq == hwirq)) - return i; - i++; - if (i >= irq_virq_count) - i = 1; - } while(i != hint); - return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); - #ifdef CONFIG_SMP int irq_choose_cpu(const struct cpumask *mask) { @@ -902,146 +535,11 @@ int irq_choose_cpu(const struct cpumask *mask) } #endif -unsigned int irq_radix_revmap_lookup(struct irq_domain *host, - irq_hw_number_t hwirq) -{ - struct irq_data *irq_data; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) - return irq_find_mapping(host, 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(&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. - */ - return irq_data ? irq_data->irq : irq_find_mapping(host, hwirq); -} - -void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - struct irq_data *irq_data = irq_get_irq_data(virq); - - if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) - return; - - if (virq != NO_IRQ) { - mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); - mutex_unlock(&revmap_trees_mutex); - } -} - -unsigned int irq_linear_revmap(struct irq_domain *host, - irq_hw_number_t hwirq) -{ - unsigned int *revmap; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_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]; -} - 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 ", 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 */ - #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 35b9ff382e45..18f4ab002d2e 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -16,6 +16,17 @@ * (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 @@ -108,6 +119,32 @@ struct irq_domain { }; #ifdef CONFIG_IRQ_DOMAIN +#ifdef CONFIG_PPC +extern struct irq_domain *irq_alloc_host(struct device_node *of_node, + unsigned int revmap_type, + unsigned int revmap_arg, + struct irq_domain_ops *ops, + irq_hw_number_t inval_irq); +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); + + +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); + +#else /* CONFIG_PPC */ + /** * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number * @@ -137,15 +174,16 @@ extern void irq_domain_add(struct irq_domain *domain); extern void irq_domain_del(struct irq_domain *domain); extern struct irq_domain_ops irq_domain_simple_ops; -#endif /* CONFIG_IRQ_DOMAIN */ -#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ) +#if defined(CONFIG_OF_IRQ) extern void irq_domain_add_simple(struct device_node *controller, int irq_base); 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 */ +#endif /* !CONFIG_PPC */ +#endif /* CONFIG_IRQ_DOMAIN */ #endif /* _LINUX_IRQDOMAIN_H */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 509adb8762d7..f551bc1d3167 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1,14 +1,612 @@ +#include +#include +#include #include +#include #include #include #include #include #include +#include #include +#include +#include static LIST_HEAD(irq_domain_list); static DEFINE_MUTEX(irq_domain_mutex); +#ifdef CONFIG_PPC +static DEFINE_MUTEX(revmap_trees_mutex); +static unsigned int irq_virq_count = NR_IRQS; +static struct irq_domain *irq_default_host; + +static int default_irq_host_match(struct irq_domain *h, struct device_node *np) +{ + return h->of_node != NULL && h->of_node == np; +} + +/** + * irq_alloc_host() - 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 + * @revmap_arg: for IRQ_DOMAIN_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_domain structure. Note that in the case of + * IRQ_DOMAIN_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_DOMAIN_MAP_LINEAR, the map is allocated by + * this call as well. For a IRQ_DOMAIN_MAP_TREE, 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_alloc_host(struct device_node *of_node, + unsigned int revmap_type, + unsigned int revmap_arg, + struct irq_domain_ops *ops, + irq_hw_number_t inval_irq) +{ + struct irq_domain *host, *h; + unsigned int size = sizeof(struct irq_domain); + unsigned int i; + unsigned int *rmap; + + /* Allocate structure and revmap table if using linear mapping */ + if (revmap_type == IRQ_DOMAIN_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; + + mutex_lock(&irq_domain_mutex); + /* Make sure only one legacy controller can be created */ + if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { + list_for_each_entry(h, &irq_domain_list, link) { + if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { + mutex_unlock(&irq_domain_mutex); + of_node_put(host->of_node); + kfree(host); + return NULL; + } + } + } + list_add(&host->link, &irq_domain_list); + mutex_unlock(&irq_domain_mutex); + + /* Additional setups per revmap type */ + switch(revmap_type) { + case IRQ_DOMAIN_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++) { + struct irq_data *irq_data = irq_get_irq_data(i); + irq_data->hwirq = i; + irq_data->domain = host; + + /* 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_DOMAIN_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; + host->revmap_data.linear.revmap = rmap; + break; + case IRQ_DOMAIN_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; +} + +/** + * irq_find_host() - Locates a domain for a given device node + * @node: device-tree node of the interrupt controller + */ +struct irq_domain *irq_find_host(struct device_node *node) +{ + struct irq_domain *h, *found = NULL; + + /* 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_for_each_entry(h, &irq_domain_list, link) + if (h->ops->match(h, node)) { + 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 + * @host: default host 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 *host) +{ + pr_debug("irq: Default host set to @0x%p\n", host); + + irq_default_host = host; +} + +/** + * 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); + + BUG_ON(count < NUM_ISA_INTERRUPTS); + if (count < NR_IRQS) + irq_virq_count = count; +} + +static int irq_setup_virq(struct irq_domain *host, 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 = host; + if (host->ops->map(host, 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; +} + +/** + * irq_create_direct_mapping() - Allocate an irq for direct mapping + * @host: domain to allocate the irq 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 irq as the hardware interrupt number. + */ +unsigned int irq_create_direct_mapping(struct irq_domain *host) +{ + unsigned int virq; + + if (host == NULL) + host = irq_default_host; + + BUG_ON(host == NULL); + WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); + + virq = irq_alloc_desc_from(1, 0); + if (virq == NO_IRQ) { + pr_debug("irq: create_direct virq allocation failed\n"); + return NO_IRQ; + } + 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(host, virq, virq)) { + irq_free_desc(virq); + return NO_IRQ; + } + + return virq; +} + +/** + * irq_create_mapping() - Map a hardware interrupt into linux irq 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 + * 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 *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_DOMAIN_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; + if (hint == 0) + hint++; + virq = irq_alloc_desc_from(hint, 0); + if (!virq) + virq = irq_alloc_desc_from(1, 0); + if (virq == NO_IRQ) { + pr_debug("irq: -> virq allocation failed\n"); + return NO_IRQ; + } + } + + if (irq_setup_virq(host, virq, hwirq)) { + if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) + irq_free_desc(virq); + 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_domain *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); + +/** + * 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 *host; + irq_hw_number_t hwirq; + + if (virq == NO_IRQ || !irq_data) + return; + + host = irq_data->domain; + if (WARN_ON(host == NULL)) + return; + + /* Never unmap legacy interrupts */ + if (host->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 (host->ops->unmap) + host->ops->unmap(host, virq); + smp_mb(); + + /* Clear reverse map */ + hwirq = irq_data->hwirq; + switch(host->revmap_type) { + case IRQ_DOMAIN_MAP_LINEAR: + if (hwirq < host->revmap_data.linear.size) + host->revmap_data.linear.revmap[hwirq] = NO_IRQ; + break; + case IRQ_DOMAIN_MAP_TREE: + mutex_lock(&revmap_trees_mutex); + radix_tree_delete(&host->revmap_data.tree, hwirq); + mutex_unlock(&revmap_trees_mutex); + break; + } + + /* Destroy map */ + irq_data->hwirq = host->inval_irq; + + irq_free_desc(virq); +} +EXPORT_SYMBOL_GPL(irq_dispose_mapping); + +/** + * irq_find_mapping() - Find a linux irq from an hw irq number. + * @host: domain 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. + */ +unsigned int irq_find_mapping(struct irq_domain *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_DOMAIN_MAP_LEGACY) + return 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 == host) && (data->hwirq == hwirq)) + return i; + i++; + if (i >= irq_virq_count) + i = 1; + } while(i != hint); + return NO_IRQ; +} +EXPORT_SYMBOL_GPL(irq_find_mapping); + +/** + * irq_radix_revmap_lookup() - Find a linux irq 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 + */ +unsigned int irq_radix_revmap_lookup(struct irq_domain *host, + irq_hw_number_t hwirq) +{ + struct irq_data *irq_data; + + if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) + return irq_find_mapping(host, 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(&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. + */ + return irq_data ? irq_data->irq : irq_find_mapping(host, hwirq); +} + +/** + * irq_radix_revmap_insert() - Insert a hw irq to linux irq 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. + */ +void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct irq_data *irq_data = irq_get_irq_data(virq); + + if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) + return; + + if (virq != NO_IRQ) { + mutex_lock(&revmap_trees_mutex); + radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); + mutex_unlock(&revmap_trees_mutex); + } +} + +/** + * irq_linear_revmap() - Find a linux irq 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 + */ +unsigned int irq_linear_revmap(struct irq_domain *host, + irq_hw_number_t hwirq) +{ + unsigned int *revmap; + + if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_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]; +} + +#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 ", 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 */ + +#else /* CONFIG_PPC */ + /** * irq_domain_add() - Register an irq_domain * @domain: ptr to initialized irq_domain structure @@ -185,3 +783,5 @@ struct irq_domain_ops irq_domain_simple_ops = { #endif /* CONFIG_OF_IRQ */ }; EXPORT_SYMBOL_GPL(irq_domain_simple_ops); + +#endif /* !CONFIG_PPC */ From 03848373ea741caafab952fb62405ed7fc0c279c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:52 -0700 Subject: [PATCH 09/33] irq_domain: remove NO_IRQ from irq domain code zero always means no irq when using irq domains. Get rid of the NO_IRQ references. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- kernel/irq/irqdomain.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index f551bc1d3167..8f7b91ce53c4 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -108,7 +108,7 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, case IRQ_DOMAIN_MAP_LINEAR: rmap = (unsigned int *)(host + 1); for (i = 0; i < revmap_arg; i++) - rmap[i] = NO_IRQ; + rmap[i] = 0; host->revmap_data.linear.size = revmap_arg; host->revmap_data.linear.revmap = rmap; break; @@ -218,9 +218,9 @@ unsigned int irq_create_direct_mapping(struct irq_domain *host) WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); virq = irq_alloc_desc_from(1, 0); - if (virq == NO_IRQ) { + if (!virq) { pr_debug("irq: create_direct virq allocation failed\n"); - return NO_IRQ; + return 0; } if (virq >= irq_virq_count) { pr_err("ERROR: no free irqs available below %i maximum\n", @@ -233,7 +233,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *host) if (irq_setup_virq(host, virq, virq)) { irq_free_desc(virq); - return NO_IRQ; + return 0; } return virq; @@ -263,13 +263,13 @@ unsigned int irq_create_mapping(struct irq_domain *host, printk(KERN_WARNING "irq_create_mapping called for" " NULL host, hwirq=%lx\n", hwirq); WARN_ON(1); - return NO_IRQ; + return 0; } pr_debug("irq: -> using host @%p\n", host); /* Check if mapping already exists */ virq = irq_find_mapping(host, hwirq); - if (virq != NO_IRQ) { + if (virq) { pr_debug("irq: -> existing mapping on virq %d\n", virq); return virq; } @@ -279,7 +279,7 @@ unsigned int irq_create_mapping(struct irq_domain *host, /* Handle legacy */ virq = (unsigned int)hwirq; if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) - return NO_IRQ; + return 0; return virq; } else { /* Allocate a virtual interrupt number */ @@ -289,16 +289,16 @@ unsigned int irq_create_mapping(struct irq_domain *host, virq = irq_alloc_desc_from(hint, 0); if (!virq) virq = irq_alloc_desc_from(1, 0); - if (virq == NO_IRQ) { + if (!virq) { pr_debug("irq: -> virq allocation failed\n"); - return NO_IRQ; + return 0; } } if (irq_setup_virq(host, virq, hwirq)) { if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) irq_free_desc(virq); - return NO_IRQ; + return 0; } pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", @@ -323,7 +323,7 @@ unsigned int irq_create_of_mapping(struct device_node *controller, if (host == NULL) { printk(KERN_WARNING "irq: no irq host found for %s !\n", controller->full_name); - return NO_IRQ; + return 0; } /* If host has no translation, then we assume interrupt line */ @@ -332,12 +332,12 @@ unsigned int irq_create_of_mapping(struct device_node *controller, else { if (host->ops->xlate(host, controller, intspec, intsize, &hwirq, &type)) - return NO_IRQ; + return 0; } /* Create mapping */ virq = irq_create_mapping(host, hwirq); - if (virq == NO_IRQ) + if (!virq) return virq; /* Set type if specified and different than the current one */ @@ -358,7 +358,7 @@ void irq_dispose_mapping(unsigned int virq) struct irq_domain *host; irq_hw_number_t hwirq; - if (virq == NO_IRQ || !irq_data) + if (!virq || !irq_data) return; host = irq_data->domain; @@ -387,7 +387,7 @@ void irq_dispose_mapping(unsigned int virq) switch(host->revmap_type) { case IRQ_DOMAIN_MAP_LINEAR: if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; + host->revmap_data.linear.revmap[hwirq] = 0; break; case IRQ_DOMAIN_MAP_TREE: mutex_lock(&revmap_trees_mutex); @@ -422,7 +422,7 @@ unsigned int irq_find_mapping(struct irq_domain *host, if (host == NULL) host = irq_default_host; if (host == NULL) - return NO_IRQ; + return 0; /* legacy -> bail early */ if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) @@ -440,7 +440,7 @@ unsigned int irq_find_mapping(struct irq_domain *host, if (i >= irq_virq_count) i = 1; } while(i != hint); - return NO_IRQ; + return 0; } EXPORT_SYMBOL_GPL(irq_find_mapping); @@ -493,7 +493,7 @@ void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) return; - if (virq != NO_IRQ) { + if (virq) { mutex_lock(&revmap_trees_mutex); radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); mutex_unlock(&revmap_trees_mutex); @@ -527,7 +527,7 @@ unsigned int irq_linear_revmap(struct irq_domain *host, return irq_find_mapping(host, hwirq); /* Fill up revmap with slow path if no mapping found */ - if (unlikely(revmap[hwirq] == NO_IRQ)) + if (unlikely(!revmap[hwirq])) revmap[hwirq] = irq_find_mapping(host, hwirq); return revmap[hwirq]; From 68700650e71b6bb6636673f4f9c8ec807353d8d6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:53 -0700 Subject: [PATCH 10/33] irq_domain: Remove references to old irq_host names No functional changes. Replaces non-exported references to 'host' with domain. Does not change any symbol names referenced by other .c files. Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- kernel/irq/irqdomain.c | 219 ++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 111 deletions(-) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8f7b91ce53c4..432d292b33f8 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -19,11 +19,11 @@ static DEFINE_MUTEX(irq_domain_mutex); #ifdef CONFIG_PPC static DEFINE_MUTEX(revmap_trees_mutex); static unsigned int irq_virq_count = NR_IRQS; -static struct irq_domain *irq_default_host; +static struct irq_domain *irq_default_domain; -static int default_irq_host_match(struct irq_domain *h, struct device_node *np) +static int default_irq_domain_match(struct irq_domain *d, struct device_node *np) { - return h->of_node != NULL && h->of_node == np; + return d->of_node != NULL && d->of_node == np; } /** @@ -31,8 +31,8 @@ static int default_irq_host_match(struct irq_domain *h, struct device_node *np) * @of_node: optional device-tree node of the interrupt controller * @revmap_type: type of reverse mapping to use * @revmap_arg: for IRQ_DOMAIN_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 + * @ops: map/unmap domain callbacks + * @inval_irq: provide a hw number in that domain space that is always invalid * * Allocates and initialize and irq_domain structure. Note that in the case of * IRQ_DOMAIN_MAP_LEGACY, the map() callback will be called before this returns @@ -48,7 +48,7 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, struct irq_domain_ops *ops, irq_hw_number_t inval_irq) { - struct irq_domain *host, *h; + struct irq_domain *domain, *h; unsigned int size = sizeof(struct irq_domain); unsigned int i; unsigned int *rmap; @@ -56,18 +56,18 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, /* Allocate structure and revmap table if using linear mapping */ if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) size += revmap_arg * sizeof(unsigned int); - host = kzalloc(size, GFP_KERNEL); - if (host == NULL) + domain = kzalloc(size, GFP_KERNEL); + if (domain == 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); + domain->revmap_type = revmap_type; + domain->inval_irq = inval_irq; + domain->ops = ops; + domain->of_node = of_node_get(of_node); - if (host->ops->match == NULL) - host->ops->match = default_irq_host_match; + if (domain->ops->match == NULL) + domain->ops->match = default_irq_domain_match; mutex_lock(&irq_domain_mutex); /* Make sure only one legacy controller can be created */ @@ -75,53 +75,53 @@ struct irq_domain *irq_alloc_host(struct device_node *of_node, list_for_each_entry(h, &irq_domain_list, link) { if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { mutex_unlock(&irq_domain_mutex); - of_node_put(host->of_node); - kfree(host); + of_node_put(domain->of_node); + kfree(domain); return NULL; } } } - list_add(&host->link, &irq_domain_list); + list_add(&domain->link, &irq_domain_list); mutex_unlock(&irq_domain_mutex); /* Additional setups per revmap type */ switch(revmap_type) { case IRQ_DOMAIN_MAP_LEGACY: /* 0 is always the invalid number for legacy */ - host->inval_irq = 0; - /* setup us as the host for all legacy interrupts */ + domain->inval_irq = 0; + /* setup us as the domain for all legacy interrupts */ for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { struct irq_data *irq_data = irq_get_irq_data(i); irq_data->hwirq = i; - irq_data->domain = host; + irq_data->domain = domain; /* 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); + ops->map(domain, i, i); /* Clear norequest flags */ irq_clear_status_flags(i, IRQ_NOREQUEST); } break; case IRQ_DOMAIN_MAP_LINEAR: - rmap = (unsigned int *)(host + 1); + rmap = (unsigned int *)(domain + 1); for (i = 0; i < revmap_arg; i++) rmap[i] = 0; - host->revmap_data.linear.size = revmap_arg; - host->revmap_data.linear.revmap = rmap; + domain->revmap_data.linear.size = revmap_arg; + domain->revmap_data.linear.revmap = rmap; break; case IRQ_DOMAIN_MAP_TREE: - INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); + INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL); break; default: break; } - pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); + pr_debug("irq: Allocated domain of type %d @0x%p\n", revmap_type, domain); - return host; + return domain; } /** @@ -150,18 +150,18 @@ EXPORT_SYMBOL_GPL(irq_find_host); /** * irq_set_default_host() - Set a "default" irq domain - * @host: default host pointer + * @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 *host) +void irq_set_default_host(struct irq_domain *domain) { - pr_debug("irq: Default host set to @0x%p\n", host); + pr_debug("irq: Default domain set to @0x%p\n", domain); - irq_default_host = host; + irq_default_domain = domain; } /** @@ -180,14 +180,14 @@ void irq_set_virq_count(unsigned int count) irq_virq_count = count; } -static int irq_setup_virq(struct irq_domain *host, unsigned int virq, +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 = host; - if (host->ops->map(host, virq, 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; @@ -201,21 +201,21 @@ static int irq_setup_virq(struct irq_domain *host, unsigned int virq, /** * irq_create_direct_mapping() - Allocate an irq for direct mapping - * @host: domain to allocate the irq for or NULL for default host + * @domain: domain to allocate the irq for or NULL for default domain * * 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 *host) +unsigned int irq_create_direct_mapping(struct irq_domain *domain) { unsigned int virq; - if (host == NULL) - host = irq_default_host; + if (domain == NULL) + domain = irq_default_domain; - BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_NOMAP); + BUG_ON(domain == NULL); + WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP); virq = irq_alloc_desc_from(1, 0); if (!virq) { @@ -231,7 +231,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *host) pr_debug("irq: create_direct obtained virq %d\n", virq); - if (irq_setup_virq(host, virq, virq)) { + if (irq_setup_virq(domain, virq, virq)) { irq_free_desc(virq); return 0; } @@ -241,41 +241,41 @@ unsigned int irq_create_direct_mapping(struct irq_domain *host) /** * irq_create_mapping() - Map a hardware interrupt into linux irq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space + * @domain: domain owning this hardware interrupt or NULL for default domain + * @hwirq: hardware irq number in that domain space * * 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 *host, +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", host, hwirq); + pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) { + /* 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 host, hwirq=%lx\n", hwirq); + " NULL domain, hwirq=%lx\n", hwirq); WARN_ON(1); return 0; } - pr_debug("irq: -> using host @%p\n", host); + pr_debug("irq: -> using domain @%p\n", domain); /* Check if mapping already exists */ - virq = irq_find_mapping(host, hwirq); + 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 (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) { + if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) { /* Handle legacy */ virq = (unsigned int)hwirq; if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) @@ -295,14 +295,14 @@ unsigned int irq_create_mapping(struct irq_domain *host, } } - if (irq_setup_virq(host, virq, hwirq)) { - if (host->revmap_type != IRQ_DOMAIN_MAP_LEGACY) + 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 host %s mapped to virtual irq %u\n", - hwirq, host->of_node ? host->of_node->full_name : "null", virq); + 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; } @@ -311,32 +311,29 @@ 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 *host; + struct irq_domain *domain; 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", + domain = controller ? irq_find_host(controller) : irq_default_domain; + if (!domain) { + printk(KERN_WARNING "irq: no irq domain found for %s !\n", controller->full_name); return 0; } - /* If host has no translation, then we assume interrupt line */ - if (host->ops->xlate == NULL) + /* If domain has no translation, then we assume interrupt line */ + if (domain->ops->xlate == NULL) hwirq = intspec[0]; else { - if (host->ops->xlate(host, controller, intspec, intsize, + if (domain->ops->xlate(domain, controller, intspec, intsize, &hwirq, &type)) return 0; } /* Create mapping */ - virq = irq_create_mapping(host, hwirq); + virq = irq_create_mapping(domain, hwirq); if (!virq) return virq; @@ -355,18 +352,18 @@ EXPORT_SYMBOL_GPL(irq_create_of_mapping); void irq_dispose_mapping(unsigned int virq) { struct irq_data *irq_data = irq_get_irq_data(virq); - struct irq_domain *host; + struct irq_domain *domain; irq_hw_number_t hwirq; if (!virq || !irq_data) return; - host = irq_data->domain; - if (WARN_ON(host == NULL)) + domain = irq_data->domain; + if (WARN_ON(domain == NULL)) return; /* Never unmap legacy interrupts */ - if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) + if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) return; irq_set_status_flags(virq, IRQ_NOREQUEST); @@ -378,26 +375,26 @@ void irq_dispose_mapping(unsigned int virq) synchronize_irq(virq); /* Tell the PIC about it */ - if (host->ops->unmap) - host->ops->unmap(host, virq); + if (domain->ops->unmap) + domain->ops->unmap(domain, virq); smp_mb(); /* Clear reverse map */ hwirq = irq_data->hwirq; - switch(host->revmap_type) { + switch(domain->revmap_type) { case IRQ_DOMAIN_MAP_LINEAR: - if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = 0; + 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(&host->revmap_data.tree, hwirq); + radix_tree_delete(&domain->revmap_data.tree, hwirq); mutex_unlock(&revmap_trees_mutex); break; } /* Destroy map */ - irq_data->hwirq = host->inval_irq; + irq_data->hwirq = domain->inval_irq; irq_free_desc(virq); } @@ -405,27 +402,27 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping); /** * irq_find_mapping() - Find a linux irq from an hw irq number. - * @host: domain owning this hardware interrupt - * @hwirq: hardware irq number in that host space + * @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 *host, +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 host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) + /* Look for default domain if nececssary */ + if (domain == NULL) + domain = irq_default_domain; + if (domain == NULL) return 0; /* legacy -> bail early */ - if (host->revmap_type == IRQ_DOMAIN_MAP_LEGACY) + if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) return hwirq; /* Slow path does a linear search of the map */ @@ -434,7 +431,7 @@ unsigned int irq_find_mapping(struct irq_domain *host, i = hint; do { struct irq_data *data = irq_get_irq_data(i); - if (data && (data->domain == host) && (data->hwirq == hwirq)) + if (data && (data->domain == domain) && (data->hwirq == hwirq)) return i; i++; if (i >= irq_virq_count) @@ -446,26 +443,26 @@ EXPORT_SYMBOL_GPL(irq_find_mapping); /** * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space + * @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 radix tree * revmaps */ -unsigned int irq_radix_revmap_lookup(struct irq_domain *host, +unsigned int irq_radix_revmap_lookup(struct irq_domain *domain, irq_hw_number_t hwirq) { struct irq_data *irq_data; - if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) - return irq_find_mapping(host, hwirq); + 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(&host->revmap_data.tree, hwirq); + irq_data = radix_tree_lookup(&domain->revmap_data.tree, hwirq); rcu_read_unlock(); /* @@ -473,62 +470,62 @@ unsigned int irq_radix_revmap_lookup(struct irq_domain *host, * 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(host, hwirq); + return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq); } /** * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping. - * @host: host owning this hardware interrupt + * @domain: domain owning this hardware interrupt * @virq: linux irq number - * @hwirq: hardware irq number in that host space + * @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 *host, unsigned int virq, +void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) { struct irq_data *irq_data = irq_get_irq_data(virq); - if (WARN_ON(host->revmap_type != IRQ_DOMAIN_MAP_TREE)) + if (WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_TREE)) return; if (virq) { mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, irq_data); + 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. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space + * @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 *host, +unsigned int irq_linear_revmap(struct irq_domain *domain, irq_hw_number_t hwirq) { unsigned int *revmap; - if (WARN_ON_ONCE(host->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) - return irq_find_mapping(host, hwirq); + if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) + return irq_find_mapping(domain, hwirq); /* Check revmap bounds */ - if (unlikely(hwirq >= host->revmap_data.linear.size)) - return irq_find_mapping(host, hwirq); + if (unlikely(hwirq >= domain->revmap_data.linear.size)) + return irq_find_mapping(domain, hwirq); /* Check if revmap was allocated */ - revmap = host->revmap_data.linear.revmap; + revmap = domain->revmap_data.linear.revmap; if (unlikely(revmap == NULL)) - return irq_find_mapping(host, hwirq); + 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(host, hwirq); + revmap[hwirq] = irq_find_mapping(domain, hwirq); return revmap[hwirq]; } @@ -544,7 +541,7 @@ static int virq_debug_show(struct seq_file *m, void *private) int i; seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", - "chip name", "chip data", "host name"); + "chip name", "chip data", "domain name"); for (i = 1; i < nr_irqs; i++) { desc = irq_to_desc(i); From a8db8cf0d894df5f1dcfd4bce9894e0dbcc01c96 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:54 -0700 Subject: [PATCH 11/33] irq_domain: Replace irq_alloc_host() with revmap-specific initializers Each revmap type has different arguments for setting up the revmap. This patch splits up the generator functions so that each revmap type can do its own setup and the user doesn't need to keep track of how each revmap type handles the arguments. This patch also adds a host_data argument to the generators. There are cases where the host_data pointer will be needed before the function returns. ie. the legacy map calls the .map callback for each irq before returning. v2: - Add void *host_data argument to irq_domain_add_*() functions - fixed failure to compile - Moved IRQ_DOMAIN_MAP_* defines into irqdomain.c Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- .../powerpc/platforms/512x/mpc5121_ads_cpld.c | 3 +- arch/powerpc/platforms/52xx/media5200.c | 7 +- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 6 +- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 4 +- arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 6 +- .../platforms/85xx/socrates_fpga_pic.c | 5 +- arch/powerpc/platforms/86xx/gef_pic.c | 5 +- arch/powerpc/platforms/cell/axon_msi.c | 5 +- arch/powerpc/platforms/cell/beat_interrupt.c | 4 +- arch/powerpc/platforms/cell/interrupt.c | 4 +- arch/powerpc/platforms/cell/spider-pic.c | 6 +- .../platforms/embedded6xx/flipper-pic.c | 6 +- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 5 +- arch/powerpc/platforms/iseries/irq.c | 3 +- arch/powerpc/platforms/powermac/pic.c | 5 +- arch/powerpc/platforms/powermac/smp.c | 3 +- arch/powerpc/platforms/ps3/interrupt.c | 3 +- arch/powerpc/platforms/wsp/opb_pic.c | 7 +- arch/powerpc/sysdev/cpm1.c | 3 +- arch/powerpc/sysdev/cpm2_pic.c | 3 +- arch/powerpc/sysdev/ehv_pic.c | 6 +- arch/powerpc/sysdev/fsl_msi.c | 6 +- arch/powerpc/sysdev/i8259.c | 3 +- arch/powerpc/sysdev/ipic.c | 7 +- arch/powerpc/sysdev/mpc8xx_pic.c | 3 +- arch/powerpc/sysdev/mpic.c | 7 +- arch/powerpc/sysdev/mv64x60_pic.c | 5 +- arch/powerpc/sysdev/qe_lib/qe_ic.c | 5 +- arch/powerpc/sysdev/tsi108_pci.c | 3 +- arch/powerpc/sysdev/uic.c | 6 +- arch/powerpc/sysdev/xics/xics-common.c | 3 +- arch/powerpc/sysdev/xilinx_intc.c | 5 +- drivers/gpio/gpio-mpc8xxx.c | 7 +- include/linux/irqdomain.h | 24 ++- kernel/irq/irqdomain.c | 196 ++++++++++++------ 35 files changed, 196 insertions(+), 183 deletions(-) diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index fefa7977fa9f..291d61c94718 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -190,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void) cpld_pic_node = of_node_get(np); - cpld_pic_host = - irq_alloc_host(np, IRQ_DOMAIN_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 a746415c4242..5db5cfb6a4ff 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -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_DOMAIN_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 e90af8fd8413..b53275d12727 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -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_DOMAIN_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 8c997f1a9122..41fa67126c44 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -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_DOMAIN_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 bdba174e7b3a..4ef9d6918e23 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void) out_be32(&priv->regs->mask, ~0); mb(); - host = irq_alloc_host(np, IRQ_DOMAIN_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 e3ef7c9ed7b1..1092c121adf3 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -280,9 +280,8 @@ void socrates_fpga_pic_init(struct device_node *pic) int i; /* Setup an irq_domain structure */ - socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_DOMAIN_MAP_LINEAR, - SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, - SOCRATES_FPGA_NUM_IRQS); + 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 0cf8af230bcf..126a94b530e4 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -212,9 +212,8 @@ void __init gef_pic_init(struct device_node *np) } /* Setup an irq_domain structure */ - gef_pic_irq_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, - GEF_PIC_NUM_IRQS, - &gef_pic_host_ops, NO_IRQ); + 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 1bfd18a48a7f..cf9fd3c8a9b9 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device) } memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES); - msic->irq_domain = irq_alloc_host(dn, IRQ_DOMAIN_MAP_NOMAP, - NR_IRQS, &msic_host_ops, 0); + 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_domain->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 21b64cfef5e5..bbdf57440cd5 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -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_DOMAIN_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 6888475e7c62..c844797a6898 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -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_DOMAIN_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 1f935a772ef8..6521d202284a 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -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_DOMAIN_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 f862361730fb..434597166ca4 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -159,15 +159,13 @@ struct irq_domain * __init flipper_pic_init(struct device_node *np) __flipper_quiesce(io_base); - irq_domain = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, FLIPPER_NR_IRQS, - &flipper_irq_domain_ops, -1); + 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_domain->host_data = io_base; - out: return irq_domain; } diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 2d4a5d48fbbd..499d410b95fa 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -177,13 +177,12 @@ struct irq_domain *hlwd_pic_init(struct device_node *np) __hlwd_quiesce(io_base); - irq_domain = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, HLWD_NR_IRQS, - &hlwd_irq_domain_ops, -1); + 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_domain->host_data = io_base; return irq_domain; } diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index b07d4f2e0155..5538b593079d 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -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_DOMAIN_MAP_NOMAP, 0, - &iseries_irq_domain_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 cff326ab8ef2..646fdf3b9c0c 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -352,9 +352,8 @@ static void __init pmac_pic_probe_oldstyle(void) /* * Allocate an irq host */ - pmac_pic_host = irq_alloc_host(master, IRQ_DOMAIN_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 6b1ef2d4dea0..09afd704f07a 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void) { int rc = -ENOMEM; - psurge_host = irq_alloc_host(NULL, IRQ_DOMAIN_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 c5980e422dc6..c05808f21015 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -753,8 +753,7 @@ void __init ps3_init_IRQ(void) unsigned cpu; struct irq_domain *host; - host = irq_alloc_host(NULL, IRQ_DOMAIN_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 76b33bc36116..4837515c2826 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -263,13 +263,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_DOMAIN_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 +275,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 0877a757c209..53f39dbbfb97 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -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_DOMAIN_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 b149baae5d33..b3643322c528 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -275,8 +275,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_DOMAIN_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 48d3ba1220d3..adea322ea18f 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -275,9 +275,8 @@ void __init ehv_pic_init(void) return; } - ehv_pic->irqhost = irq_alloc_host(np, IRQ_DOMAIN_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 3f9a301c4550..f4fd95bc1278 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -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_DOMAIN_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/i8259.c b/arch/powerpc/sysdev/i8259.c index 7e67890b8fc2..573a73bd954a 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -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_DOMAIN_MAP_LEGACY, - 0, &i8259_host_ops, 0); + i8259_host = irq_domain_add_legacy(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 9abed3760545..0eaaa01c11b3 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -728,9 +728,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_DOMAIN_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 +737,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/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 978dfc4c3120..d5f5416be310 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -171,8 +171,7 @@ int mpc8xx_pic_init(void) goto out; } - mpc8xx_pic_host = irq_alloc_host(np, IRQ_DOMAIN_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 c844d343bf32..c83a512fa175 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -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_DOMAIN_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/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 45124a1959d0..8848e99a83f2 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -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_DOMAIN_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 78e90192c343..e9b3d5cc65d3 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -339,8 +339,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_DOMAIN_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 +348,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/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index f3757236e666..1be26f4b9c96 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -419,8 +419,7 @@ 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_DOMAIN_MAP_LEGACY, - 0, &pci_irq_domain_ops, 0); + pci_irq_host = irq_domain_add_legacy(node, &pci_irq_domain_ops, NULL); if (pci_irq_host == NULL) { 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 7eea3a64bdf7..84e59c97391f 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -270,13 +270,11 @@ static struct uic * __init uic_init_one(struct device_node *node) } uic->dcrbase = *dcrreg; - uic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_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 fb2e303d25fb..ea5e204e3450 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -374,8 +374,7 @@ static struct irq_domain_ops xics_host_ops = { static void __init xics_init_host(void) { - xics_host = irq_alloc_host(NULL, IRQ_DOMAIN_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 92e7d4db9fde..8d73c3c0bee6 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -201,11 +201,10 @@ xilinx_intc_init(struct device_node *np) out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ /* Allocate and initialize an irq_domain structure. */ - irq = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, XILINX_INTC_MAXIRQS, - &xilinx_intc_ops, -1); + 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/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 9efd59732eeb..149d9876fca8 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -364,9 +364,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_DOMAIN_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 +373,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/include/linux/irqdomain.h b/include/linux/irqdomain.h index 18f4ab002d2e..f95553fa6872 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -95,10 +95,6 @@ struct irq_domain { /* type of reverse mapping_technique */ unsigned int revmap_type; -#define IRQ_DOMAIN_MAP_LEGACY 0 /* 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 */ union { struct { unsigned int size; @@ -120,11 +116,21 @@ struct irq_domain { #ifdef CONFIG_IRQ_DOMAIN #ifdef CONFIG_PPC -extern struct irq_domain *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_domain_ops *ops, - irq_hw_number_t inval_irq); +struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, + struct irq_domain_ops *ops, + void *host_data); +struct irq_domain *irq_domain_add_linear(struct device_node *of_node, + unsigned int size, + struct irq_domain_ops *ops, + void *host_data); +struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, + struct irq_domain_ops *ops, + void *host_data); +struct irq_domain *irq_domain_add_tree(struct device_node *of_node, + 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); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 432d292b33f8..acedba1a2651 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -13,6 +13,11 @@ #include #include +#define IRQ_DOMAIN_MAP_LEGACY 0 /* 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); @@ -27,100 +32,158 @@ static int default_irq_domain_match(struct irq_domain *d, struct device_node *np } /** - * irq_alloc_host() - Allocate a new irq_domain data 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 - * @revmap_arg: for IRQ_DOMAIN_MAP_LINEAR linear only: size of the map * @ops: map/unmap domain callbacks - * @inval_irq: provide a hw number in that domain space that is always invalid + * @host_data: Controller private data pointer * - * Allocates and initialize and irq_domain structure. Note that in the case of - * IRQ_DOMAIN_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_DOMAIN_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_DOMAIN_MAP_TREE, the radix tree will be - * allocated later during boot automatically (the reverse mapping will use the - * slow path until that happens). + * 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. */ -struct irq_domain *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_domain_ops *ops, - irq_hw_number_t inval_irq) +static struct irq_domain *irq_domain_alloc(struct device_node *of_node, + unsigned int revmap_type, + struct irq_domain_ops *ops, + void *host_data) { - struct irq_domain *domain, *h; - unsigned int size = sizeof(struct irq_domain); - unsigned int i; - unsigned int *rmap; + struct irq_domain *domain; - /* Allocate structure and revmap table if using linear mapping */ - if (revmap_type == IRQ_DOMAIN_MAP_LINEAR) - size += revmap_arg * sizeof(unsigned int); - domain = kzalloc(size, GFP_KERNEL); - if (domain == NULL) + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (WARN_ON(!domain)) return NULL; /* Fill structure */ domain->revmap_type = revmap_type; - domain->inval_irq = inval_irq; domain->ops = ops; + domain->host_data = host_data; domain->of_node = of_node_get(of_node); if (domain->ops->match == NULL) domain->ops->match = default_irq_domain_match; + 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); +} + +/** + * irq_domain_add_legacy() - 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 + * + * 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, + struct irq_domain_ops *ops, + void *host_data) +{ + struct irq_domain *domain, *h; + unsigned int i; + + domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data); + if (!domain) + return NULL; + mutex_lock(&irq_domain_mutex); /* Make sure only one legacy controller can be created */ - if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) { - list_for_each_entry(h, &irq_domain_list, link) { - if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { - mutex_unlock(&irq_domain_mutex); - of_node_put(domain->of_node); - kfree(domain); - return NULL; - } + list_for_each_entry(h, &irq_domain_list, link) { + if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { + mutex_unlock(&irq_domain_mutex); + of_node_put(domain->of_node); + kfree(domain); + return NULL; } } list_add(&domain->link, &irq_domain_list); mutex_unlock(&irq_domain_mutex); - /* Additional setups per revmap type */ - switch(revmap_type) { - case IRQ_DOMAIN_MAP_LEGACY: - /* 0 is always the invalid number for legacy */ - domain->inval_irq = 0; - /* setup us as the domain for all legacy interrupts */ - for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { - struct irq_data *irq_data = irq_get_irq_data(i); - irq_data->hwirq = i; - irq_data->domain = domain; + /* setup us as the domain for all legacy interrupts */ + for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { + struct irq_data *irq_data = irq_get_irq_data(i); + irq_data->hwirq = i; + irq_data->domain = domain; - /* Legacy flags are left to default at this point, - * one can then use irq_create_mapping() to - * explicitly change them - */ - ops->map(domain, i, i); + /* Legacy flags are left to default at this point, + * one can then use irq_create_mapping() to + * explicitly change them + */ + ops->map(domain, i, i); - /* Clear norequest flags */ - irq_clear_status_flags(i, IRQ_NOREQUEST); - } - break; - case IRQ_DOMAIN_MAP_LINEAR: - rmap = (unsigned int *)(domain + 1); - for (i = 0; i < revmap_arg; i++) - rmap[i] = 0; - domain->revmap_data.linear.size = revmap_arg; - domain->revmap_data.linear.revmap = rmap; - break; - case IRQ_DOMAIN_MAP_TREE: - INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL); - break; - default: - break; + /* Clear norequest flags */ + irq_clear_status_flags(i, IRQ_NOREQUEST); } + return domain; +} - pr_debug("irq: Allocated domain of type %d @0x%p\n", revmap_type, 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, + 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, + 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, + 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; } @@ -393,9 +456,6 @@ void irq_dispose_mapping(unsigned int virq) break; } - /* Destroy map */ - irq_data->hwirq = domain->inval_irq; - irq_free_desc(virq); } EXPORT_SYMBOL_GPL(irq_dispose_mapping); From 1bc04f2cf8c2a1feadbd994f50c40bb145bf2989 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:55 -0700 Subject: [PATCH 12/33] irq_domain: Add support for base irq and hwirq in legacy mappings Add support for a legacy mapping where irq = (hwirq - first_hwirq + first_irq) so that a controller driver can allocate a fixed range of irq_descs and use a simple calculation to translate back and forth between linux and hw irq numbers. This is needed to use an irq_domain with many of the ARM interrupt controller drivers that manage their own irq_desc allocations. Ultimately the goal is to migrate those drivers to use the linear revmap, but doing it this way allows each driver to be converted separately which makes the migration path easier. This patch generalizes the IRQ_DOMAIN_MAP_LEGACY method to use (first_irq-first_hwirq) as the offset between hwirq and linux irq number, and adds checks to make sure that the hwirq number does not exceed range assigned to the controller. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/include/asm/irq.h | 3 - arch/powerpc/sysdev/i8259.c | 2 +- arch/powerpc/sysdev/tsi108_pci.c | 2 +- include/linux/irqdomain.h | 20 ++++++- kernel/irq/irqdomain.c | 96 +++++++++++++++++++++----------- 5 files changed, 85 insertions(+), 38 deletions(-) diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index 728cc30d04ea..fe0b09dceb7d 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -36,9 +36,6 @@ 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 diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 573a73bd954a..997df6a7ab5d 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -263,7 +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_domain_add_legacy(node, &i8259_host_ops, NULL); + 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/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 1be26f4b9c96..188012c58f7f 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -419,7 +419,7 @@ void __init tsi108_pci_int_init(struct device_node *node) { DBG("Tsi108_pci_int_init: initializing PCI interrupts\n"); - pci_irq_host = irq_domain_add_legacy(node, &pci_irq_domain_ops, NULL); + 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 domain!\n"); return; diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index f95553fa6872..7fef39ed5523 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -39,6 +39,9 @@ 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. @@ -96,6 +99,11 @@ struct irq_domain { /* 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; @@ -117,6 +125,9 @@ struct irq_domain { #ifdef CONFIG_IRQ_DOMAIN #ifdef CONFIG_PPC 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, struct irq_domain_ops *ops, void *host_data); struct irq_domain *irq_domain_add_linear(struct device_node *of_node, @@ -130,11 +141,18 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node, 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, + struct irq_domain_ops *ops, + void *host_data) +{ + return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, + host_data); +} extern unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index acedba1a2651..c6740d72073e 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -13,7 +13,8 @@ #include #include -#define IRQ_DOMAIN_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */ +#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 */ @@ -74,9 +75,25 @@ static void irq_domain_add(struct irq_domain *domain) 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 * @@ -85,44 +102,64 @@ static void irq_domain_add(struct irq_domain *domain) * 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, struct irq_domain_ops *ops, void *host_data) { - struct irq_domain *domain, *h; + 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); - /* Make sure only one legacy controller can be created */ - list_for_each_entry(h, &irq_domain_list, link) { - if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) { + /* 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; } } - list_add(&domain->link, &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); - /* setup us as the domain for all legacy interrupts */ - for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { - struct irq_data *irq_data = irq_get_irq_data(i); - irq_data->hwirq = i; - irq_data->domain = domain; + 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, i, i); + ops->map(domain, irq, hwirq); /* Clear norequest flags */ - irq_clear_status_flags(i, IRQ_NOREQUEST); + irq_clear_status_flags(irq, IRQ_NOREQUEST); } + + irq_domain_add(domain); return domain; } @@ -338,24 +375,19 @@ unsigned int irq_create_mapping(struct irq_domain *domain, } /* Get a virtual interrupt number */ - if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) { - /* Handle legacy */ - virq = (unsigned int)hwirq; - if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) - return 0; - return virq; - } else { - /* 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 (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)) { @@ -483,7 +515,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain, /* legacy -> bail early */ if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) - return hwirq; + return irq_domain_legacy_revmap(domain, hwirq); /* Slow path does a linear search of the map */ if (hint == 0) From a850a7554442f08d3e910c6eeb4ee216868dda1e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:55 -0700 Subject: [PATCH 13/33] of/address: add empty static inlines for !CONFIG_OF As the title says, this patch adds empty implementations for the address translation functions so that they can be used when CONFIG_OF is disabled. Signed-off-by: Grant Likely Cc: Rob Herring --- include/linux/of_address.h | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 3118623c2c1f..01b925ad8d78 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -4,6 +4,7 @@ #include #include +#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 */ From 5769089ac72569d024817270ab79fdf0b9046dde Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Tue, 14 Feb 2012 14:06:56 -0700 Subject: [PATCH 14/33] mfd: twl-core.c: Fix the number of interrupts managed by twl4030 TWL4030 does handle 3 different interrupts ranges: 8 for the core, 8 for the power events and 18 for the GPIOs. Change the total number of interrupts managed by TWL4030 from 8 to 34. Signed-off-by: Benoit Cousson Signed-off-by: Grant Likely --- drivers/mfd/twl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 8ce3959c6919..49677339ab5f 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[] */ From 75294957be1dee7d22dd7d90bd31334ba410e836 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:57 -0700 Subject: [PATCH 15/33] irq_domain: Remove 'new' irq_domain in favour of the ppc one This patch removes the simplistic implementation of irq_domains and enables the powerpc infrastructure for all irq_domain users. The powerpc infrastructure includes support for complex mappings between Linux and hardware irq numbers, and can manage allocation of irq_descs. This patch also converts the few users of irq_domain_add()/irq_domain_del() to call irq_domain_add_legacy() instead. v3: Fix bug that set up too many irqs in translation range. v2: Fix removal of irq_alloc_descs() call in gic driver Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/arm/common/gic.c | 85 +++++++-------- arch/arm/common/vic.c | 16 +-- arch/arm/include/asm/hardware/gic.h | 4 +- arch/arm/include/asm/hardware/vic.h | 2 + arch/arm/mach-exynos/common.c | 2 +- arch/arm/mach-versatile/core.c | 7 +- drivers/mfd/twl-core.c | 14 +-- include/linux/irqdomain.h | 45 +------- kernel/irq/irqdomain.c | 159 +++------------------------- 9 files changed, 71 insertions(+), 263 deletions(-) diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index dc19862be0a8..7275d808f76d 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,7 +597,23 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif -#ifdef CONFIG_OF +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, @@ -639,26 +634,23 @@ static int gic_irq_domain_xlate(struct irq_domain *d, *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return 0; } -#endif struct irq_domain_ops gic_irq_domain_ops = { -#ifdef CONFIG_OF + .map = gic_irq_domain_map, .xlate = gic_irq_domain_xlate, -#endif }; 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->host_data = 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 dcb004a804c7..7a66311f3066 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 4bdfe0018696..4b1ce6cd477f 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 f42ebd619590..e14af1a1a320 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 c59e18871006..6de298c5d2d3 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-versatile/core.c b/arch/arm/mach-versatile/core.c index 02b7b9303f3b..008ce22b9a06 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/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 49677339ab5f..66f9bffc50f0 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -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"); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 7fef39ed5523..624e9ac89e79 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -55,9 +55,6 @@ typedef unsigned long irq_hw_number_t; * @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 - * @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) * @xlate: Given a device tree node and interrupt specifier, decode * the hardware irq number and linux irq type value. * @@ -70,7 +67,6 @@ struct irq_domain_ops { 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); - unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq); int (*xlate)(struct irq_domain *d, struct device_node *node, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type); @@ -114,16 +110,11 @@ struct irq_domain { void *host_data; irq_hw_number_t inval_irq; - unsigned int irq_base; - unsigned int nr_irq; - unsigned int hwirq_base; - /* Optional device node pointer */ struct device_node *of_node; }; #ifdef CONFIG_IRQ_DOMAIN -#ifdef CONFIG_PPC struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, unsigned int size, unsigned int first_irq, @@ -153,6 +144,10 @@ static inline struct irq_domain *irq_domain_add_legacy_isa( 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); + extern unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq); @@ -167,38 +162,7 @@ extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, extern unsigned int irq_linear_revmap(struct irq_domain *host, irq_hw_number_t hwirq); -#else /* CONFIG_PPC */ - -/** - * 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) -{ - 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; -} - -#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 void irq_domain_add(struct irq_domain *domain); -extern void irq_domain_del(struct irq_domain *domain); - extern struct irq_domain_ops irq_domain_simple_ops; - #if defined(CONFIG_OF_IRQ) extern void irq_domain_add_simple(struct device_node *controller, int irq_base); extern void irq_domain_generate_simple(const struct of_device_id *match, @@ -207,7 +171,6 @@ extern void irq_domain_generate_simple(const struct of_device_id *match, static inline void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start) { } #endif /* !CONFIG_OF_IRQ */ -#endif /* !CONFIG_PPC */ #endif /* CONFIG_IRQ_DOMAIN */ #endif /* _LINUX_IRQDOMAIN_H */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index c6740d72073e..2981ebfeb40c 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -22,7 +22,6 @@ static LIST_HEAD(irq_domain_list); static DEFINE_MUTEX(irq_domain_mutex); -#ifdef CONFIG_PPC static DEFINE_MUTEX(revmap_trees_mutex); static unsigned int irq_virq_count = NR_IRQS; static struct irq_domain *irq_default_domain; @@ -694,125 +693,12 @@ static int __init irq_debugfs_init(void) __initcall(irq_debugfs_init); #endif /* CONFIG_VIRQ_DEBUG */ -#else /* CONFIG_PPC */ - -/** - * irq_domain_add() - Register an irq_domain - * @domain: ptr to initialized irq_domain structure - * - * 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. - */ -void irq_domain_add(struct irq_domain *domain) +int irq_domain_simple_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { - struct irq_data *d; - int hwirq, irq; - - /* - * 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; - } - d->domain = domain; - d->hwirq = hwirq; - } - - mutex_lock(&irq_domain_mutex); - list_add(&domain->link, &irq_domain_list); - mutex_unlock(&irq_domain_mutex); + return 0; } -/** - * irq_domain_del() - Unregister an irq_domain - * @domain: ptr to registered irq_domain. - */ -void irq_domain_del(struct irq_domain *domain) -{ - struct irq_data *d; - int hwirq, irq; - - mutex_lock(&irq_domain_mutex); - list_del(&domain->link); - mutex_unlock(&irq_domain_mutex); - - /* Clear the irq_domain assignments */ - irq_domain_for_each_irq(domain, hwirq, irq) { - d = irq_get_irq_data(irq); - d->domain = NULL; - } -} - -#if defined(CONFIG_OF_IRQ) -/** - * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec - * - * 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. - * - * When the caller no longer need the irq number returned by this function it - * should arrange to call irq_dispose_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; - - /* Find a domain which can translate the irq spec */ - mutex_lock(&irq_domain_mutex); - list_for_each_entry(domain, &irq_domain_list, link) { - if (!domain->ops->xlate) - continue; - rc = domain->ops->xlate(domain, controller, - intspec, intsize, &hwirq, &type); - if (rc == 0) - break; - } - mutex_unlock(&irq_domain_mutex); - - if (rc != 0) - return 0; - - 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; -} -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 - * - * 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(). - */ -void irq_dispose_mapping(unsigned int irq) -{ - /* - * nothing yet; will be filled when support for dynamic allocation of - * irq_descs is added to irq_domain - */ -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - int irq_domain_simple_xlate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, @@ -822,10 +708,6 @@ int irq_domain_simple_xlate(struct irq_domain *d, 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; - *out_hwirq = intspec[0]; *out_type = IRQ_TYPE_NONE; if (intsize > 1) @@ -833,23 +715,17 @@ int irq_domain_simple_xlate(struct irq_domain *d, return 0; } -/** - * irq_domain_create_simple() - Set up a 'simple' translation range - */ +struct irq_domain_ops irq_domain_simple_ops = { + .map = irq_domain_simple_map, + .xlate = irq_domain_simple_xlate, +}; +EXPORT_SYMBOL_GPL(irq_domain_simple_ops); + +#ifdef CONFIG_OF_IRQ void irq_domain_add_simple(struct device_node *controller, int irq_base) { - struct irq_domain *domain; - - domain = kzalloc(sizeof(*domain), GFP_KERNEL); - if (!domain) { - WARN_ON(1); - return; - } - - domain->irq_base = irq_base; - domain->of_node = of_node_get(controller); - domain->ops = &irq_domain_simple_ops; - irq_domain_add(domain); + irq_domain_add_legacy(controller, 32, irq_base, 0, + &irq_domain_simple_ops, NULL); } EXPORT_SYMBOL_GPL(irq_domain_add_simple); @@ -864,13 +740,4 @@ void irq_domain_generate_simple(const struct of_device_id *match, irq_domain_add_simple(node, irq_start); } EXPORT_SYMBOL_GPL(irq_domain_generate_simple); -#endif /* CONFIG_OF_IRQ */ - -struct irq_domain_ops irq_domain_simple_ops = { -#ifdef CONFIG_OF_IRQ - .xlate = irq_domain_simple_xlate, -#endif /* CONFIG_OF_IRQ */ -}; -EXPORT_SYMBOL_GPL(irq_domain_simple_ops); - -#endif /* !CONFIG_PPC */ +#endif From 6b783f7c5dde2648fa0bbe7fc8ac80d78699e67f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 10 Jan 2012 17:09:30 -0700 Subject: [PATCH 16/33] irq_domain: Remove irq_domain_add_simple() irq_domain_add_simple() was a stop-gap measure until complete irq_domain support was complete. This patch removes the irq_domain_add_simple() interface. This patch also drops the explicit irq_domain initialization performed by the mach-versatile code because the versatile interrupt controller already has irq_domain support built into it. This was a bug that was hanging around quietly for a while, but with the full irq_domain which actually verifies that irq_domain ranges are available it would cause the registration to fail and the system wouldn't boot. v4: Fixed number of irqs in mx5 gpio code v2: Updated to pass in host_data pointer on irq_domain allocation. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Thomas Gleixner Cc: Milton Miller Cc: Russell King Tested-by: Olof Johansson --- arch/arm/mach-imx/imx51-dt.c | 4 ++-- arch/arm/mach-imx/imx53-dt.c | 4 ++-- arch/arm/mach-imx/mach-imx6q.c | 3 ++- arch/arm/mach-msm/board-msm8x60.c | 8 ++------ arch/arm/mach-omap2/board-generic.c | 2 +- arch/arm/mach-prima2/irq.c | 2 +- include/linux/irqdomain.h | 1 - kernel/irq/irqdomain.c | 10 ++-------- 8 files changed, 12 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index e6bad17b908c..1e03ef42faa0 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 05ebb3e68679..fd5be0f20fbb 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 c25728106917..6075d4d62dd6 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 0a113424632c..962e71169750 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 d58756060483..00b1d024fa87 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -67,7 +67,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 d93ceef4a50a..37c2de9b6f26 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/include/linux/irqdomain.h b/include/linux/irqdomain.h index 624e9ac89e79..e7379a3c4d7d 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -164,7 +164,6 @@ extern unsigned int irq_linear_revmap(struct irq_domain *host, extern struct irq_domain_ops irq_domain_simple_ops; #if defined(CONFIG_OF_IRQ) -extern void irq_domain_add_simple(struct device_node *controller, int irq_base); extern void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start); #else /* CONFIG_OF_IRQ */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 2981ebfeb40c..6328d9350f04 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -722,13 +722,6 @@ struct irq_domain_ops irq_domain_simple_ops = { EXPORT_SYMBOL_GPL(irq_domain_simple_ops); #ifdef CONFIG_OF_IRQ -void irq_domain_add_simple(struct device_node *controller, int irq_base) -{ - irq_domain_add_legacy(controller, 32, irq_base, 0, - &irq_domain_simple_ops, NULL); -} -EXPORT_SYMBOL_GPL(irq_domain_add_simple); - void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start) { @@ -737,7 +730,8 @@ void irq_domain_generate_simple(const struct of_device_id *match, (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); + irq_domain_add_legacy(node, 32, irq_start, 0, + &irq_domain_simple_ops, NULL); } EXPORT_SYMBOL_GPL(irq_domain_generate_simple); #endif From 16b2e6e2f31dda41f114aa0acade04f7e10f67c9 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 26 Jan 2012 11:26:52 -0700 Subject: [PATCH 17/33] irq_domain: Create common xlate functions that device drivers can use Rather than having each interrupt controller driver creating its own barely unique .xlate function for irq_domain, create a library of translators which any driver can use directly. v5: - Remove irq_domain_xlate_pci(). It was incorrect. Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Mark Salter Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- include/linux/irqdomain.h | 12 ++++++++ kernel/irq/irqdomain.c | 65 +++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index e7379a3c4d7d..ea58f36688a0 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -163,6 +163,18 @@ extern unsigned int irq_linear_revmap(struct irq_domain *host, irq_hw_number_t hwirq); extern struct irq_domain_ops irq_domain_simple_ops; + +/* 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_OF_IRQ) extern void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 6328d9350f04..456e3fc8387f 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -699,25 +699,70 @@ int irq_domain_simple_map(struct irq_domain *d, unsigned int irq, return 0; } -int irq_domain_simple_xlate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type) +/** + * 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 (d->of_node != controller) - return -EINVAL; - if (intsize < 1) + 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_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. + */ +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) +{ + 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); + +/** + * 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_xlate_onetwocell); struct irq_domain_ops irq_domain_simple_ops = { .map = irq_domain_simple_map, - .xlate = irq_domain_simple_xlate, + .xlate = irq_domain_xlate_onetwocell, }; EXPORT_SYMBOL_GPL(irq_domain_simple_ops); From a18dc81bf58258ac0920bec26b91656cb0140d2a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 26 Jan 2012 12:12:14 -0700 Subject: [PATCH 18/33] irq_domain: constify irq_domain_ops Make irq_domain_ops pointer a constant to make it safer for multiple instances to share the same ops pointer and change the irq_domain code so that it does not modify the ops. v4: Fix mismatched type reference in powerpc code Signed-off-by: Grant Likely Cc: Thomas Gleixner Cc: Benjamin Herrenschmidt Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/sysdev/mpic_msi.c | 2 +- include/linux/irqdomain.h | 14 +++++++------- kernel/irq/irqdomain.c | 31 +++++++++++++++---------------- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 00395f40fb5d..0622aa91b18a 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_domain_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/include/linux/irqdomain.h b/include/linux/irqdomain.h index ea58f36688a0..52454881938a 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -106,7 +106,7 @@ struct irq_domain { } linear; struct radix_tree_root tree; } revmap_data; - struct irq_domain_ops *ops; + const struct irq_domain_ops *ops; void *host_data; irq_hw_number_t inval_irq; @@ -119,17 +119,17 @@ 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, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data); struct irq_domain *irq_domain_add_linear(struct device_node *of_node, unsigned int size, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data); struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data); struct irq_domain *irq_domain_add_tree(struct device_node *of_node, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data); extern struct irq_domain *irq_find_host(struct device_node *node); @@ -138,7 +138,7 @@ extern void irq_set_virq_count(unsigned int count); static inline struct irq_domain *irq_domain_add_legacy_isa( struct device_node *of_node, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data) { return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, @@ -162,7 +162,7 @@ extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, extern unsigned int irq_linear_revmap(struct irq_domain *host, irq_hw_number_t hwirq); -extern struct irq_domain_ops irq_domain_simple_ops; +extern const struct irq_domain_ops irq_domain_simple_ops; /* stock xlate functions */ int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 456e3fc8387f..25a498eb98a3 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -26,11 +26,6 @@ static DEFINE_MUTEX(revmap_trees_mutex); static unsigned int irq_virq_count = NR_IRQS; static struct irq_domain *irq_default_domain; -static int default_irq_domain_match(struct irq_domain *d, struct device_node *np) -{ - return d->of_node != NULL && d->of_node == np; -} - /** * irq_domain_alloc() - Allocate a new irq_domain data structure * @of_node: optional device-tree node of the interrupt controller @@ -44,7 +39,7 @@ static int default_irq_domain_match(struct irq_domain *d, struct device_node *np */ static struct irq_domain *irq_domain_alloc(struct device_node *of_node, unsigned int revmap_type, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain; @@ -59,9 +54,6 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node, domain->host_data = host_data; domain->of_node = of_node_get(of_node); - if (domain->ops->match == NULL) - domain->ops->match = default_irq_domain_match; - return domain; } @@ -104,7 +96,7 @@ 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, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain; @@ -170,7 +162,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, */ struct irq_domain *irq_domain_add_linear(struct device_node *of_node, unsigned int size, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain; @@ -192,7 +184,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node, } struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain = irq_domain_alloc(of_node, @@ -211,7 +203,7 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, * (the reverse mapping will use the slow path until that happens). */ struct irq_domain *irq_domain_add_tree(struct device_node *of_node, - struct irq_domain_ops *ops, + const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain = irq_domain_alloc(of_node, @@ -230,6 +222,7 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node, struct irq_domain *irq_find_host(struct device_node *node) { 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 @@ -237,11 +230,17 @@ struct irq_domain *irq_find_host(struct device_node *node) * yet though... */ mutex_lock(&irq_domain_mutex); - list_for_each_entry(h, &irq_domain_list, link) - if (h->ops->match(h, node)) { + 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; } @@ -760,7 +759,7 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, } EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell); -struct irq_domain_ops irq_domain_simple_ops = { +const struct irq_domain_ops irq_domain_simple_ops = { .map = irq_domain_simple_map, .xlate = irq_domain_xlate_onetwocell, }; From 0bd761e1b6d909d3fd08841be7d5035f9fde8a53 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Thu, 26 Jan 2012 09:26:21 -0500 Subject: [PATCH 19/33] irq_domain/c6x: Convert c6x to use generic irq_domain support. The C6X IRQ support was copied almost verbatim from the PowerPC virtual IRQ code. The PowerPC code was used as the basis for generic irq_domain support, so this patch mostly copies what what done to arch/powerpc by Grant Likely in his irq_domain patch series. Signed-off-by: Mark Salter Signed-off-by: Grant Likely Cc: Aurelien Jacquiot Cc: Thomas Gleixner --- arch/c6x/Kconfig | 1 + arch/c6x/include/asm/irq.h | 245 +------------ arch/c6x/kernel/irq.c | 611 +------------------------------ arch/c6x/platforms/megamod-pic.c | 13 +- 4 files changed, 21 insertions(+), 849 deletions(-) diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index 26e67f0f0051..3c64b2894c13 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 a6ae3c9d9c40..f13b78d5e1ca 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 #include #include #include @@ -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 0929e4b2b244..3d5ac600a38b 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,8 @@ 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 struct irq_domain_ops core_domain_ops = { + .map = core_domain_map, }; void __init init_IRQ(void) @@ -100,10 +100,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 +129,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 7c37a947fb1c..61f5863f1b1d 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,7 +136,7 @@ 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, +static int megamod_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) @@ -148,7 +148,7 @@ static int megamod_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops megamod_host_ops = { +static struct irq_domain_ops megamod_domain_ops = { .map = megamod_map, .xlate = megamod_xlate, }; @@ -223,9 +223,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; From 15a25980d450c81e514c2a8724b575461961a30d Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 26 Jan 2012 12:25:18 -0700 Subject: [PATCH 20/33] irq_domain/c6x: constify irq_domain structures Signed-off-by: Grant Likely Cc: Mark Salter Cc: Thomas Gleixner --- arch/arm/common/gic.c | 2 +- arch/c6x/kernel/irq.c | 2 +- arch/c6x/platforms/megamod-pic.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 7275d808f76d..f0783be17352 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -635,7 +635,7 @@ static int gic_irq_domain_xlate(struct irq_domain *d, return 0; } -struct irq_domain_ops gic_irq_domain_ops = { +const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, .xlate = gic_irq_domain_xlate, }; diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c index 3d5ac600a38b..c6b36e86a010 100644 --- a/arch/c6x/kernel/irq.c +++ b/arch/c6x/kernel/irq.c @@ -86,7 +86,7 @@ static int core_domain_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops core_domain_ops = { +static const struct irq_domain_ops core_domain_ops = { .map = core_domain_map, }; diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 61f5863f1b1d..9f35fbf2df3e 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -148,7 +148,7 @@ static int megamod_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_ops megamod_domain_ops = { +static const struct irq_domain_ops megamod_domain_ops = { .map = megamod_map, .xlate = megamod_xlate, }; From c1e572e6506082ed120a13454b2cc2f525ee7aa6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 26 Jan 2012 08:40:09 -0700 Subject: [PATCH 21/33] irq_domain/c6x: Use library of xlate functions The c6x irq controllers don't need to define custom .xlate hooks Signed-off-by: Grant Likely Cc: Rob Herring Cc: Mark Salter Cc: Thomas Gleixner --- arch/c6x/kernel/irq.c | 1 + arch/c6x/platforms/megamod-pic.c | 14 +------------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c index c6b36e86a010..d77bcfdf0d8e 100644 --- a/arch/c6x/kernel/irq.c +++ b/arch/c6x/kernel/irq.c @@ -88,6 +88,7 @@ static int core_domain_map(struct irq_domain *h, unsigned int virq, static const struct irq_domain_ops core_domain_ops = { .map = core_domain_map, + .xlate = irq_domain_xlate_onecell, }; void __init init_IRQ(void) diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 9f35fbf2df3e..c1c4e2ae3f85 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -136,21 +136,9 @@ static int megamod_map(struct irq_domain *h, unsigned int virq, return 0; } -static int megamod_xlate(struct irq_domain *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 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) From 9f70b8eb3cd37c6ef3371f972db799250e3eb86e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 26 Jan 2012 12:24:34 -0700 Subject: [PATCH 22/33] irq_domain/powerpc: constify irq_domain_ops Make all the irq_domain_ops structures in powerpc 'static const' Signed-off-by: Grant Likely Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 2 +- arch/powerpc/platforms/52xx/media5200.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 2 +- arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 2 +- arch/powerpc/platforms/85xx/socrates_fpga_pic.c | 2 +- arch/powerpc/platforms/86xx/gef_pic.c | 2 +- arch/powerpc/platforms/cell/axon_msi.c | 2 +- arch/powerpc/platforms/cell/beat_interrupt.c | 2 +- arch/powerpc/platforms/cell/interrupt.c | 2 +- arch/powerpc/platforms/cell/spider-pic.c | 2 +- arch/powerpc/platforms/embedded6xx/flipper-pic.c | 2 +- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 2 +- arch/powerpc/platforms/iseries/irq.c | 2 +- arch/powerpc/platforms/powermac/pic.c | 2 +- arch/powerpc/platforms/powermac/smp.c | 2 +- arch/powerpc/platforms/ps3/interrupt.c | 2 +- arch/powerpc/platforms/wsp/opb_pic.c | 2 +- arch/powerpc/sysdev/cpm1.c | 2 +- arch/powerpc/sysdev/cpm2_pic.c | 2 +- arch/powerpc/sysdev/ehv_pic.c | 2 +- arch/powerpc/sysdev/fsl_msi.c | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 291d61c94718..ca3a062ed1b9 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -137,7 +137,7 @@ cpld_pic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_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, }; diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 5db5cfb6a4ff..17d91b7da315 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_ops media5200_irq_ops = { +static const struct irq_domain_ops media5200_irq_ops = { .map = media5200_irq_map, .xlate = media5200_irq_xlate, }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index b53275d12727..028470b95886 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_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, }; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 41fa67126c44..8520b58a5e9a 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops mpc52xx_irqhost_ops = { +static const struct irq_domain_ops mpc52xx_irqhost_ops = { .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 4ef9d6918e23..328d221fd1c0 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -112,7 +112,7 @@ static int pci_pic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops pci_pic_host_ops = { +static const struct irq_domain_ops pci_pic_host_ops = { .map = pci_pic_host_map, }; diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 1092c121adf3..3bbbf7489487 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_domain *h, return 0; } -static struct irq_domain_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, }; diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 126a94b530e4..af3fd697de82 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_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, }; diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index cf9fd3c8a9b9..db360fc4cf0e 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -327,7 +327,7 @@ static int msic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops msic_host_ops = { +static const struct irq_domain_ops msic_host_ops = { .map = msic_host_map, }; diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index bbdf57440cd5..e5c3a2c6090d 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -172,7 +172,7 @@ static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np) return 1; } -static struct irq_domain_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, diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index c844797a6898..2d42f3bb66d6 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_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, diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 6521d202284a..d8b7cc8a66ca 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_ops spider_host_ops = { +static const struct irq_domain_ops spider_host_ops = { .map = spider_host_map, .xlate = spider_host_xlate, }; diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 434597166ca4..675335a52648 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -113,7 +113,7 @@ static int flipper_pic_match(struct irq_domain *h, struct device_node *np) } -static struct irq_domain_ops flipper_irq_domain_ops = { +static const struct irq_domain_ops flipper_irq_domain_ops = { .map = flipper_pic_map, .match = flipper_pic_match, }; diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 499d410b95fa..da6ca02c43ac 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -100,7 +100,7 @@ static int hlwd_pic_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops hlwd_irq_domain_ops = { +static const struct irq_domain_ops hlwd_irq_domain_ops = { .map = hlwd_pic_map, }; diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 5538b593079d..05ce5164cafc 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -356,7 +356,7 @@ static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np) return 1; } -static struct irq_domain_ops iseries_irq_domain_ops = { +static const struct irq_domain_ops iseries_irq_domain_ops = { .map = iseries_irq_host_map, .match = iseries_irq_host_match, }; diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 646fdf3b9c0c..46a5f32e958b 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -299,7 +299,7 @@ static int pmac_pic_host_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_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, diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 09afd704f07a..a81e5a88fbdf 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_domain *h, unsigned int virq, return 0; } -struct irq_domain_ops psurge_host_ops = { +static const struct irq_domain_ops psurge_host_ops = { .map = psurge_host_map, }; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index c05808f21015..2a4ff86cc21f 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -684,7 +684,7 @@ static int ps3_host_match(struct irq_domain *h, struct device_node *np) return 1; } -static struct irq_domain_ops ps3_host_ops = { +static const struct irq_domain_ops ps3_host_ops = { .map = ps3_host_map, .match = ps3_host_match, }; diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index 4837515c2826..0c6fe0b50137 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -207,7 +207,7 @@ static int opb_host_xlate(struct irq_domain *host, struct device_node *dn, return 0; } -static struct irq_domain_ops opb_host_ops = { +static const struct irq_domain_ops opb_host_ops = { .map = opb_host_map, .xlate = opb_host_xlate, }; diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 53f39dbbfb97..d4fa03f2b6ac 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = { .name = "error", }; -static struct irq_domain_ops cpm_pic_host_ops = { +static const struct irq_domain_ops cpm_pic_host_ops = { .map = cpm_pic_host_map, }; diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index b3643322c528..8c9fc9c29095 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -236,7 +236,7 @@ static int cpm2_pic_host_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_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, }; diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index adea322ea18f..6e0e1005227f 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct, return 0; } -static struct irq_domain_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, diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index f4fd95bc1278..0c01debe963b 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops fsl_msi_host_ops = { +static const struct irq_domain_ops fsl_msi_host_ops = { .map = fsl_msi_host_map, }; From ff8c3ab8161d0df52858966e0347e05791da40df Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 24 Jan 2012 17:09:13 -0700 Subject: [PATCH 23/33] irq_domain/powerpc: Replace custom xlate functions with library functions This patch converts a number of the powerpc drivers to use the common library of irq_domain xlate functions, dropping a bunch of lines in the process. v5: - Remove tsi108 changes from patch Signed-off-by: Grant Likely Cc: Rob Herring Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller Tested-by: Olof Johansson --- arch/powerpc/platforms/powermac/pic.c | 13 +------------ arch/powerpc/platforms/wsp/opb_pic.c | 13 +------------ arch/powerpc/sysdev/cpm2_pic.c | 14 +------------- arch/powerpc/sysdev/ipic.c | 18 +----------------- arch/powerpc/sysdev/qe_lib/qe_ic.c | 15 +-------------- arch/powerpc/sysdev/uic.c | 14 +------------- drivers/gpio/gpio-mpc8xxx.c | 17 +---------------- 7 files changed, 7 insertions(+), 97 deletions(-) diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 46a5f32e958b..92afc382a49e 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static int pmac_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) - -{ - *out_flags = IRQ_TYPE_NONE; - *out_hwirq = *intspec; - return 0; -} - 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) diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index 0c6fe0b50137..cb565bf93650 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -196,20 +196,9 @@ static int opb_host_map(struct irq_domain *host, unsigned int virq, return 0; } -static int opb_host_xlate(struct irq_domain *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 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) diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 8c9fc9c29095..d3be961e2ae7 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static int cpm2_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) -{ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - 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) diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 0eaaa01c11b3..b50f97811c25 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static int ipic_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) - -{ - /* 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_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) diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index e9b3d5cc65d3..2fba6ef2f95e 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static int qe_ic_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) -{ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - 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. */ diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 84e59c97391f..92033936a8f7 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -190,21 +190,9 @@ static int uic_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static int uic_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_type) - -{ - /* UIC intspecs must have 2 cells */ - BUG_ON(intsize != 2); - *out_hwirq = intspec[0]; - *out_type = intspec[1]; - return 0; -} - 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) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 149d9876fca8..e6568c19c939 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, return 0; } -static int mpc8xxx_gpio_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) - -{ - /* 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_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 = { From 2462bacd0334d918f9fcd79fc59c403b76b36f8a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 26 Jan 2012 14:10:13 -0700 Subject: [PATCH 24/33] irq_domain/microblaze: Convert microblaze to use irq_domains This patch converts Microblaze to use the irq_domain remapper and get away from hard coding the offset between hwirq number and the linux irq number space. This also paves the way for multiple interrupt controllers. v2: Don't enable SPARSE_IRQ and keep NR_IRQS set to 33 Signed-off-by: Grant Likely Signed-off-by: Michal Simek Cc: Rob Herring Cc: John Williams Cc: John Linn --- arch/microblaze/Kconfig | 1 + arch/microblaze/include/asm/hardirq.h | 16 ------- arch/microblaze/include/asm/irq.h | 42 ++---------------- arch/microblaze/kernel/intc.c | 63 ++++++++++++++++----------- arch/microblaze/kernel/irq.c | 24 ++-------- 5 files changed, 46 insertions(+), 100 deletions(-) diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index c8d6efb99dbf..11060fa87da3 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 cd1ac9aad56c..fb3c05a0cbbf 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 - -#endif /* _ASM_MICROBLAZE_HARDIRQ_H */ diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index 7798ad14c610..bab3b1393ad4 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 -/* 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_domain; - -/** - * 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_domain *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 44b177e2ab12..ad120672cee5 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -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) -{ - int irq; +static struct irq_domain *root_domain; - /* - * 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); +unsigned int get_irq(void) +{ + unsigned int hwirq, irq = -1; + + 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 3f613dfe5a07..ace700afbfdf 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_domain *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); From 6d166fec12967063e0e709a935bba8c48fcde99e Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 22 Feb 2012 18:35:03 -0500 Subject: [PATCH 25/33] ppc-6xx: fix build failure in flipper-pic.c and hlwd-pic.c The commit bae1d8f19983fbfa25559aa3cb6a81a84aa82a18 (linux-next) "irq_domain/powerpc: Use common irq_domain structure instead of irq_host" made this change: -static struct irq_host *flipper_irq_host; +static struct irq_domain *flipper_irq_host; and this change: -static struct irq_host *hlwd_irq_host; +static struct irq_domain *hlwd_irq_host; The intent was to change the type, and not the name, but then in a couple of instances, it looks like the sed to change the irq_domain_ops name inadvertently also changed the irq_host name where it was not supposed to, causing build failures. Signed-off-by: Paul Gortmaker Signed-off-by: Grant Likely --- arch/powerpc/platforms/embedded6xx/flipper-pic.c | 6 +++--- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 675335a52648..53d6eee01963 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -172,7 +172,7 @@ out: unsigned int flipper_pic_get_irq(void) { - void __iomem *io_base = flipper_irq_domain->host_data; + void __iomem *io_base = flipper_irq_host->host_data; int irq; u32 irq_status; @@ -182,7 +182,7 @@ unsigned int flipper_pic_get_irq(void) return NO_IRQ; /* no more IRQs pending */ irq = __ffs(irq_status); - return irq_linear_revmap(flipper_irq_domain, irq); + return irq_linear_revmap(flipper_irq_host, irq); } /* @@ -197,7 +197,7 @@ void __init flipper_pic_probe(void) np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-pic"); BUG_ON(!np); - flipper_irq_domain = flipper_pic_init(np); + flipper_irq_host = flipper_pic_init(np); BUG_ON(!flipper_irq_host); irq_set_default_host(flipper_irq_host); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index da6ca02c43ac..3006b5117ec6 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -189,7 +189,7 @@ struct irq_domain *hlwd_pic_init(struct device_node *np) unsigned int hlwd_pic_get_irq(void) { - return __hlwd_pic_get_irq(hlwd_irq_domain); + return __hlwd_pic_get_irq(hlwd_irq_host); } /* @@ -213,7 +213,7 @@ void hlwd_pic_probe(void) irq_set_handler_data(cascade_virq, host); irq_set_chained_handler(cascade_virq, hlwd_pic_irq_cascade); - hlwd_irq_domain = host; + hlwd_irq_host = host; break; } } @@ -227,7 +227,7 @@ void hlwd_pic_probe(void) */ void hlwd_quiesce(void) { - void __iomem *io_base = hlwd_irq_domain->host_data; + void __iomem *io_base = hlwd_irq_host->host_data; __hlwd_quiesce(io_base); } From b4e518547da042fdc65bd4bdafd046fed13337d5 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 16 Dec 2011 15:50:17 -0700 Subject: [PATCH 26/33] irq_domain/x86: Convert x86 (embedded) to use common irq_domain This patch removes the x86-specific definition of irq_domain and replaces it with the common implementation. Signed-off-by: Grant Likely Acked-by: Sebastian Andrzej Siewior Cc: Rob Herring Cc: Thomas Gleixner --- arch/x86/Kconfig | 2 + arch/x86/include/asm/irq_controller.h | 12 --- arch/x86/include/asm/prom.h | 10 --- arch/x86/kernel/devicetree.c | 101 ++++++++------------------ drivers/net/phy/mdio-gpio.c | 4 +- 5 files changed, 34 insertions(+), 95 deletions(-) delete mode 100644 arch/x86/include/asm/irq_controller.h diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5bed94e189fa..e0829a6a4660 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 423bbbddf36d..000000000000 --- 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 644dd885f05a..60bef663609a 100644 --- a/arch/x86/include/asm/prom.h +++ b/arch/x86/include/asm/prom.h @@ -21,7 +21,6 @@ #include #include #include -#include #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 52821799a702..3ae2ced4a874 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -17,64 +18,14 @@ #include #include -#include #include #include __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; + line = intspec[0]; - intspec++; - type = *intspec; - - 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; - id = kzalloc(sizeof(*id), GFP_KERNEL); + gsi_cfg = mp_ioapic_gsi_routing(i); + + 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/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 50e8e5e74465..7189adf54bd1 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 = { From abd2363f6a5f1030b935e0bdc15cf917313b3b10 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 24 Feb 2012 08:07:06 -0700 Subject: [PATCH 27/33] irq_domain/mips: Allow irq_domain on MIPS This patch makes IRQ_DOMAIN usable on MIPS. It uses an ugly workaround to preserve current behaviour so that MIPS has time to add irq_domain registration to the irq controller drivers. The workaround will be removed in Linux v3.6 Signed-off-by: Grant Likely Cc: Ralf Baechle Cc: Rob Herring Cc: Thomas Gleixner Cc: linux-mips@linux-mips.org --- arch/mips/Kconfig | 1 + arch/mips/include/asm/irq.h | 5 +---- arch/mips/kernel/prom.c | 14 -------------- kernel/irq/irqdomain.c | 12 ++++++++++++ 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5ab6e89603c5..edbbae17e820 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 2354c870a63a..fb698dc09bc9 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -11,15 +11,12 @@ #include #include +#include #include #include -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 6b8b4208481e..558b5395795d 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/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 25a498eb98a3..af48e59bc2ff 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -411,6 +411,18 @@ unsigned int irq_create_of_mapping(struct device_node *controller, 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; From d593f25ff263b1a7752b7380f8b7d57809206c40 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 24 Feb 2012 08:24:17 -0700 Subject: [PATCH 28/33] irq_domain: Centralize definition of irq_dispose_mapping() Several architectures define their own empty irq_dispose_mapping(). Since the irq_domain code is centralized now, there is little need to do so. This patch removes them and creates a new empty copy when !CONFIG_IRQ_DOMAIN is selected. The patch also means that IRQ_DOMAIN becomes selectable on all architectures. Signed-off-by: Grant Likely Cc: Rob Herring Cc: "David S. Miller" Cc: Jonas Bonn Cc: sparclinux@vger.kernel.org Cc: linux@lists.openrisc.net --- arch/openrisc/include/asm/prom.h | 10 +--------- arch/sparc/include/asm/prom.h | 10 +--------- include/linux/irqdomain.h | 5 ++++- include/linux/of_irq.h | 4 +--- 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h index e1f3fe26606c..bbb34e5343a2 100644 --- a/arch/openrisc/include/asm/prom.h +++ b/arch/openrisc/include/asm/prom.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -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/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index edd3d3cde460..c28765110706 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -22,6 +22,7 @@ #include #include #include +#include #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/include/linux/irqdomain.h b/include/linux/irqdomain.h index 52454881938a..ead4a4215797 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -182,6 +182,9 @@ extern void irq_domain_generate_simple(const struct of_device_id *match, static inline void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start) { } #endif /* !CONFIG_OF_IRQ */ -#endif /* CONFIG_IRQ_DOMAIN */ + +#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_irq.h b/include/linux/of_irq.h index d0307eed20c9..d229ad3edee0 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -6,6 +6,7 @@ struct of_irq; #include #include #include +#include #include #include @@ -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); From 964dba283439a4db50dae61d3afe6e438b7fc30f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 24 Feb 2012 14:58:34 -0700 Subject: [PATCH 29/33] devicetree: Add empty of_platform_populate() for !CONFIG_OF_ADDRESS (sparc) Sparc has its own helpers for translating address ranges when the device tree is parsed at boot time, and it isn't able to use of_platform_populate(). However, there are some device drivers that want to use that function on other DT enabled platforms (ie. TWL4030). This patch adds an empty of_platform_populate() implementation that returns an error when CONFIG_OF_ADDRESS is not selected. Signed-off-by: Grant Likely Cc: Benoit Cousson Cc: Samuel Ortiz --- drivers/mfd/twl-core.c | 5 ++--- drivers/of/platform.c | 4 ++-- include/linux/of_platform.h | 12 ++++++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 66f9bffc50f0..4970d43952db 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1305,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/of/platform.c b/drivers/of/platform.c index 63b3ec48c203..20fbebd49db3 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -55,7 +55,7 @@ EXPORT_SYMBOL(of_find_device_by_node); #include #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/of_platform.h b/include/linux/of_platform.h index 040ce2f6e8de..242fa3563e2e 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 */ From 280ad7fda5f95211857fda38960f2b6fdf6edd3e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 24 Feb 2012 14:58:54 -0700 Subject: [PATCH 30/33] mfd: twl-core: Add IRQ_DOMAIN dependency TWL4030 depends on IRQ_DOMAIN support, so this patch selects it in Kconfig. It used to be that CONFIG_IRQ_DOMAIN must only be selected by the architecture, but recent cleanups have fixed it so that it is safe to select from anywhere. Signed-off-by: Benoit Cousson [grant.likely: Changed from a depends to a select] Signed-off-by: Grant Likely Cc: Samuel Ortiz --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f147395bac9a..1489c3540f96 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 From 52fa212088b141dd05957dc4b7f06a893c8166ad Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 30 Nov 2011 19:21:07 +0100 Subject: [PATCH 31/33] ARM: OMAP2/3: intc: Add DT support for TI interrupt controller Add a function to initialize the OMAP2/3 interrupt controller (INTC) using a device tree node. This version take advantage of the new irq_domain_add_legacy API. Replace some printk() with the proper pr_ macro. Signed-off-by: Benoit Cousson Cc: Tony Lindgren Acked-by: Rob Herring Acked-by: Grant Likely --- .../devicetree/bindings/arm/omap/intc.txt | 27 +++++++++ arch/arm/mach-omap2/common.h | 12 ++++ arch/arm/mach-omap2/irq.c | 60 +++++++++++++++---- 3 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/omap/intc.txt diff --git a/Documentation/devicetree/bindings/arm/omap/intc.txt b/Documentation/devicetree/bindings/arm/omap/intc.txt new file mode 100644 index 000000000000..f2583e6ec060 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/omap/intc.txt @@ -0,0 +1,27 @@ +* OMAP Interrupt Controller + +OMAP2/3 are using a TI interrupt controller that can support several +configurable number of interrupts. + +Main node required properties: + +- compatible : should be: + "ti,omap2-intc" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 1. + + The cell contains the interrupt number in the range [0-128]. +- ti,intc-size: Number of interrupts handled by the interrupt controller. +- reg: physical base address and size of the intc registers map. + +Example: + + intc: interrupt-controller@1 { + compatible = "ti,omap2-intc"; + interrupt-controller; + #interrupt-cells = <1>; + ti,intc-size = <96>; + reg = <0x48200000 0x1000>; + }; + diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index febffde2ff10..dd8c9906b1ab 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -174,6 +174,18 @@ void omap3_intc_handle_irq(struct pt_regs *regs); extern void __iomem *omap4_get_l2cache_base(void); #endif +struct device_node; +#ifdef CONFIG_OF +int __init omap_intc_of_init(struct device_node *node, + struct device_node *parent); +#else +int __init omap_intc_of_init(struct device_node *node, + struct device_node *parent) +{ + return 0; +} +#endif + #ifdef CONFIG_SMP extern void __iomem *omap4_get_scu_base(void); #else diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index 1fef061f7927..26eaf37ce4d9 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -11,12 +11,16 @@ * for more details. */ #include +#include #include #include #include #include #include #include +#include +#include +#include /* selected INTC register offsets */ @@ -57,6 +61,8 @@ static struct omap_irq_bank { }, }; +static struct irq_domain *domain; + /* Structure to save interrupt controller context */ struct omap3_intc_regs { u32 sysconfig; @@ -147,17 +153,27 @@ omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static void __init omap_init_irq(u32 base, int nr_irqs) +static void __init omap_init_irq(u32 base, int nr_irqs, + struct device_node *node) { void __iomem *omap_irq_base; unsigned long nr_of_irqs = 0; unsigned int nr_banks = 0; - int i, j; + int i, j, irq_base; omap_irq_base = ioremap(base, SZ_4K); if (WARN_ON(!omap_irq_base)) return; + irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); + if (irq_base < 0) { + pr_warn("Couldn't allocate IRQ numbers\n"); + irq_base = 0; + } + + domain = irq_domain_add_legacy(node, nr_irqs, irq_base, 0, + &irq_domain_simple_ops, NULL); + for (i = 0; i < ARRAY_SIZE(irq_banks); i++) { struct omap_irq_bank *bank = irq_banks + i; @@ -166,36 +182,36 @@ static void __init omap_init_irq(u32 base, int nr_irqs) /* Static mapping, never released */ bank->base_reg = ioremap(base, SZ_4K); if (!bank->base_reg) { - printk(KERN_ERR "Could not ioremap irq bank%i\n", i); + pr_err("Could not ioremap irq bank%i\n", i); continue; } omap_irq_bank_init_one(bank); for (j = 0; j < bank->nr_irqs; j += 32) - omap_alloc_gc(bank->base_reg + j, j, 32); + omap_alloc_gc(bank->base_reg + j, j + irq_base, 32); nr_of_irqs += bank->nr_irqs; nr_banks++; } - printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n", - nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : ""); + pr_info("Total of %ld interrupts on %d active controller%s\n", + nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : ""); } void __init omap2_init_irq(void) { - omap_init_irq(OMAP24XX_IC_BASE, 96); + omap_init_irq(OMAP24XX_IC_BASE, 96, NULL); } void __init omap3_init_irq(void) { - omap_init_irq(OMAP34XX_IC_BASE, 96); + omap_init_irq(OMAP34XX_IC_BASE, 96, NULL); } void __init ti81xx_init_irq(void) { - omap_init_irq(OMAP34XX_IC_BASE, 128); + omap_init_irq(OMAP34XX_IC_BASE, 128, NULL); } static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs) @@ -225,8 +241,10 @@ out: irqnr = readl_relaxed(base_addr + INTCPS_SIR_IRQ_OFFSET); irqnr &= ACTIVEIRQ_MASK; - if (irqnr) + if (irqnr) { + irqnr = irq_find_mapping(domain, irqnr); handle_IRQ(irqnr, regs); + } } while (irqnr); } @@ -236,6 +254,28 @@ asmlinkage void __exception_irq_entry omap2_intc_handle_irq(struct pt_regs *regs omap_intc_handle_irq(base_addr, regs); } +int __init omap_intc_of_init(struct device_node *node, + struct device_node *parent) +{ + struct resource res; + u32 nr_irqs = 96; + + if (WARN_ON(!node)) + return -ENODEV; + + if (of_address_to_resource(node, 0, &res)) { + WARN(1, "unable to get intc registers\n"); + return -EINVAL; + } + + if (of_property_read_u32(node, "ti,intc-size", &nr_irqs)) + pr_warn("unable to get intc-size, default to %d\n", nr_irqs); + + omap_init_irq(res.start, nr_irqs, of_node_get(node)); + + return 0; +} + #ifdef CONFIG_ARCH_OMAP3 static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)]; From d65c5423544d2d5a66dcd1c7a8630d3e32ff595b Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 30 Nov 2011 19:26:42 +0100 Subject: [PATCH 32/33] arm/dts: OMAP3: Add interrupt-controller bindings for INTC Update the DTS with the proper information required by the INTC bindings. - Add the number of interrupt lines - Add the reg and the compatible entries. Signed-off-by: Benoit Cousson Acked-by: Rob Herring Acked-by: Grant Likely --- arch/arm/boot/dts/omap3.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index e69806432874..c6121357c1eb 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -61,10 +61,12 @@ ranges; ti,hwmods = "l3_main"; - intc: interrupt-controller@1 { - compatible = "ti,omap3-intc"; + intc: interrupt-controller@48200000 { + compatible = "ti,omap2-intc"; interrupt-controller; #interrupt-cells = <1>; + ti,intc-size = <96>; + reg = <0x48200000 0x1000>; }; uart1: serial@4806a000 { From fbf75da733e82bb17a01e1b907b0e40d9c028823 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 21 Sep 2011 23:30:31 +0200 Subject: [PATCH 33/33] ARM: OMAP2+: board-generic: Use of_irq_init API Use the of_irq_init API introduced in 3.2 to handle interrupt-controller with DT. Update the irq_match table to map the proper XXX_of_init functions for INTC and GIC drivers. Signed-off-by: Benoit Cousson Cc: Tony Lindgren Acked-by: Rob Herring Acked-by: Grant Likely --- arch/arm/mach-omap2/board-generic.c | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 02d7e828a14b..12f4c5ff23bb 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include @@ -24,6 +25,17 @@ #include "common.h" #include "common-board-devices.h" +static struct of_device_id irq_match[] __initdata = { + { .compatible = "ti,omap2-intc", .data = omap_intc_of_init, }, + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + { } +}; + +static void __init omap_init_irq(void) +{ + of_irq_init(irq_match); +} + /* * XXX: Still needed to boot until the i2c & twl driver is adapted to * device-tree @@ -58,18 +70,8 @@ static struct of_device_id omap_dt_match_table[] __initdata = { { } }; -static struct of_device_id intc_match[] __initdata = { - { .compatible = "ti,omap3-intc", }, - { .compatible = "arm,cortex-a9-gic", }, - { } -}; - static void __init omap_generic_init(void) { - struct device_node *node = of_find_matching_node(NULL, intc_match); - if (node) - irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL); - omap_sdrc_init(NULL, NULL); of_platform_populate(NULL, omap_dt_match_table, NULL, NULL); @@ -101,7 +103,7 @@ DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)") .reserve = omap_reserve, .map_io = omap242x_map_io, .init_early = omap2420_init_early, - .init_irq = omap2_init_irq, + .init_irq = omap_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = omap_generic_init, .timer = &omap2_timer, @@ -120,7 +122,7 @@ DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)") .reserve = omap_reserve, .map_io = omap243x_map_io, .init_early = omap2430_init_early, - .init_irq = omap2_init_irq, + .init_irq = omap_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = omap_generic_init, .timer = &omap2_timer, @@ -139,7 +141,7 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)") .reserve = omap_reserve, .map_io = omap3_map_io, .init_early = omap3430_init_early, - .init_irq = omap3_init_irq, + .init_irq = omap_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3_init, .timer = &omap3_timer, @@ -158,7 +160,7 @@ DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") .reserve = omap_reserve, .map_io = omap4_map_io, .init_early = omap4430_init_early, - .init_irq = gic_init_irq, + .init_irq = omap_init_irq, .handle_irq = gic_handle_irq, .init_machine = omap4_init, .timer = &omap4_timer,