From bae1d8f19983fbfa25559aa3cb6a81a84aa82a18 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:50 -0700 Subject: 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/kernel/irq.c | 78 +++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'arch/powerpc/kernel/irq.c') 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; -- cgit From 4bbdd45afdae208a7c4ade89cf602f89a6397cff Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:51 -0700 Subject: 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/kernel/irq.c | 240 +++++++++++++--------------------------------- 1 file changed, 69 insertions(+), 171 deletions(-) (limited to 'arch/powerpc/kernel/irq.c') 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); -- cgit From 6d9285b00f776eebe459a858ebf07b56c36c60d2 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 14 Feb 2012 14:06:51 -0700 Subject: 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/kernel/irq.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch/powerpc/kernel/irq.c') 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; -- cgit From cc79ca691c292e9fd44f589c7940b9654e22f2f6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 16 Feb 2012 01:37:49 -0700 Subject: 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/kernel/irq.c | 502 ---------------------------------------------- 1 file changed, 502 deletions(-) (limited to 'arch/powerpc/kernel/irq.c') 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) { -- cgit