Merge tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6
Pull irqdomain changes from Grant Likely: "Minor changes and fixups for irqdomain infrastructure. The most important change adds the ability to remove a registered irqdomain." * tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6: irqdomain: Document size parameter of irq_domain_add_linear() irqdomain: trivial pr_fmt conversion. irqdomain: Kill off duplicate definitions. irqdomain: Make irq_domain_simple_map() static. irqdomain: Export remaining public API symbols. irqdomain: Support removal of IRQ domains.
This commit is contained in:
@@ -141,9 +141,8 @@ static inline struct irq_domain *irq_domain_add_legacy_isa(
|
|||||||
return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
|
return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
|
||||||
host_data);
|
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_domain_remove(struct irq_domain *host);
|
||||||
|
|
||||||
extern unsigned int irq_create_mapping(struct irq_domain *host,
|
extern unsigned int irq_create_mapping(struct irq_domain *host,
|
||||||
irq_hw_number_t hwirq);
|
irq_hw_number_t hwirq);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
#define pr_fmt(fmt) "irq: " fmt
|
||||||
|
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
@@ -56,15 +58,74 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
|
|||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void irq_domain_free(struct irq_domain *domain)
|
||||||
|
{
|
||||||
|
of_node_put(domain->of_node);
|
||||||
|
kfree(domain);
|
||||||
|
}
|
||||||
|
|
||||||
static void irq_domain_add(struct irq_domain *domain)
|
static void irq_domain_add(struct irq_domain *domain)
|
||||||
{
|
{
|
||||||
mutex_lock(&irq_domain_mutex);
|
mutex_lock(&irq_domain_mutex);
|
||||||
list_add(&domain->link, &irq_domain_list);
|
list_add(&domain->link, &irq_domain_list);
|
||||||
mutex_unlock(&irq_domain_mutex);
|
mutex_unlock(&irq_domain_mutex);
|
||||||
pr_debug("irq: Allocated domain of type %d @0x%p\n",
|
pr_debug("Allocated domain of type %d @0x%p\n",
|
||||||
domain->revmap_type, domain);
|
domain->revmap_type, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* irq_domain_remove() - Remove an irq domain.
|
||||||
|
* @domain: domain to remove
|
||||||
|
*
|
||||||
|
* This routine is used to remove an irq domain. The caller must ensure
|
||||||
|
* that all mappings within the domain have been disposed of prior to
|
||||||
|
* use, depending on the revmap type.
|
||||||
|
*/
|
||||||
|
void irq_domain_remove(struct irq_domain *domain)
|
||||||
|
{
|
||||||
|
mutex_lock(&irq_domain_mutex);
|
||||||
|
|
||||||
|
switch (domain->revmap_type) {
|
||||||
|
case IRQ_DOMAIN_MAP_LEGACY:
|
||||||
|
/*
|
||||||
|
* Legacy domains don't manage their own irq_desc
|
||||||
|
* allocations, we expect the caller to handle irq_desc
|
||||||
|
* freeing on their own.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
case IRQ_DOMAIN_MAP_TREE:
|
||||||
|
/*
|
||||||
|
* radix_tree_delete() takes care of destroying the root
|
||||||
|
* node when all entries are removed. Shout if there are
|
||||||
|
* any mappings left.
|
||||||
|
*/
|
||||||
|
WARN_ON(domain->revmap_data.tree.height);
|
||||||
|
break;
|
||||||
|
case IRQ_DOMAIN_MAP_LINEAR:
|
||||||
|
kfree(domain->revmap_data.linear.revmap);
|
||||||
|
domain->revmap_data.linear.size = 0;
|
||||||
|
break;
|
||||||
|
case IRQ_DOMAIN_MAP_NOMAP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&domain->link);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the going away domain is the default one, reset it.
|
||||||
|
*/
|
||||||
|
if (unlikely(irq_default_domain == domain))
|
||||||
|
irq_set_default_host(NULL);
|
||||||
|
|
||||||
|
mutex_unlock(&irq_domain_mutex);
|
||||||
|
|
||||||
|
pr_debug("Removed domain of type %d @0x%p\n",
|
||||||
|
domain->revmap_type, domain);
|
||||||
|
|
||||||
|
irq_domain_free(domain);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_domain_remove);
|
||||||
|
|
||||||
static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
|
static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
|
||||||
irq_hw_number_t hwirq)
|
irq_hw_number_t hwirq)
|
||||||
{
|
{
|
||||||
@@ -117,8 +178,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
|
|||||||
|
|
||||||
if (WARN_ON(!irq_data || irq_data->domain)) {
|
if (WARN_ON(!irq_data || irq_data->domain)) {
|
||||||
mutex_unlock(&irq_domain_mutex);
|
mutex_unlock(&irq_domain_mutex);
|
||||||
of_node_put(domain->of_node);
|
irq_domain_free(domain);
|
||||||
kfree(domain);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,10 +212,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
|
|||||||
irq_domain_add(domain);
|
irq_domain_add(domain);
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
|
* irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
|
||||||
* @of_node: pointer to interrupt controller's device tree node.
|
* @of_node: pointer to interrupt controller's device tree node.
|
||||||
|
* @size: Number of interrupts in the domain.
|
||||||
* @ops: map/unmap domain callbacks
|
* @ops: map/unmap domain callbacks
|
||||||
* @host_data: Controller private data pointer
|
* @host_data: Controller private data pointer
|
||||||
*/
|
*/
|
||||||
@@ -181,6 +243,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
|
|||||||
irq_domain_add(domain);
|
irq_domain_add(domain);
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_domain_add_linear);
|
||||||
|
|
||||||
struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
|
struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
|
||||||
unsigned int max_irq,
|
unsigned int max_irq,
|
||||||
@@ -195,6 +258,7 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
|
|||||||
}
|
}
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_domain_add_nomap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_domain_add_tree()
|
* irq_domain_add_tree()
|
||||||
@@ -216,6 +280,7 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
|
|||||||
}
|
}
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_domain_add_tree);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_find_host() - Locates a domain for a given device node
|
* irq_find_host() - Locates a domain for a given device node
|
||||||
@@ -259,10 +324,11 @@ EXPORT_SYMBOL_GPL(irq_find_host);
|
|||||||
*/
|
*/
|
||||||
void irq_set_default_host(struct irq_domain *domain)
|
void irq_set_default_host(struct irq_domain *domain)
|
||||||
{
|
{
|
||||||
pr_debug("irq: Default domain set to @0x%p\n", domain);
|
pr_debug("Default domain set to @0x%p\n", domain);
|
||||||
|
|
||||||
irq_default_domain = domain;
|
irq_default_domain = domain;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_set_default_host);
|
||||||
|
|
||||||
static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
|
static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
|
||||||
irq_hw_number_t hwirq)
|
irq_hw_number_t hwirq)
|
||||||
@@ -272,7 +338,7 @@ static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
|
|||||||
irq_data->hwirq = hwirq;
|
irq_data->hwirq = hwirq;
|
||||||
irq_data->domain = domain;
|
irq_data->domain = domain;
|
||||||
if (domain->ops->map(domain, virq, hwirq)) {
|
if (domain->ops->map(domain, virq, hwirq)) {
|
||||||
pr_debug("irq: -> mapping failed, freeing\n");
|
pr_debug("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq);
|
||||||
irq_data->domain = NULL;
|
irq_data->domain = NULL;
|
||||||
irq_data->hwirq = 0;
|
irq_data->hwirq = 0;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -303,7 +369,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
|
|||||||
|
|
||||||
virq = irq_alloc_desc_from(1, 0);
|
virq = irq_alloc_desc_from(1, 0);
|
||||||
if (!virq) {
|
if (!virq) {
|
||||||
pr_debug("irq: create_direct virq allocation failed\n");
|
pr_debug("create_direct virq allocation failed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (virq >= domain->revmap_data.nomap.max_irq) {
|
if (virq >= domain->revmap_data.nomap.max_irq) {
|
||||||
@@ -312,7 +378,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
|
|||||||
irq_free_desc(virq);
|
irq_free_desc(virq);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pr_debug("irq: create_direct obtained virq %d\n", virq);
|
pr_debug("create_direct obtained virq %d\n", virq);
|
||||||
|
|
||||||
if (irq_setup_virq(domain, virq, virq)) {
|
if (irq_setup_virq(domain, virq, virq)) {
|
||||||
irq_free_desc(virq);
|
irq_free_desc(virq);
|
||||||
@@ -321,6 +387,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
|
|||||||
|
|
||||||
return virq;
|
return virq;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_create_mapping() - Map a hardware interrupt into linux irq space
|
* irq_create_mapping() - Map a hardware interrupt into linux irq space
|
||||||
@@ -338,23 +405,23 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
|
|||||||
unsigned int hint;
|
unsigned int hint;
|
||||||
int virq;
|
int virq;
|
||||||
|
|
||||||
pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
|
pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
|
||||||
|
|
||||||
/* Look for default domain if nececssary */
|
/* Look for default domain if nececssary */
|
||||||
if (domain == NULL)
|
if (domain == NULL)
|
||||||
domain = irq_default_domain;
|
domain = irq_default_domain;
|
||||||
if (domain == NULL) {
|
if (domain == NULL) {
|
||||||
printk(KERN_WARNING "irq_create_mapping called for"
|
pr_warning("irq_create_mapping called for"
|
||||||
" NULL domain, hwirq=%lx\n", hwirq);
|
" NULL domain, hwirq=%lx\n", hwirq);
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pr_debug("irq: -> using domain @%p\n", domain);
|
pr_debug("-> using domain @%p\n", domain);
|
||||||
|
|
||||||
/* Check if mapping already exists */
|
/* Check if mapping already exists */
|
||||||
virq = irq_find_mapping(domain, hwirq);
|
virq = irq_find_mapping(domain, hwirq);
|
||||||
if (virq) {
|
if (virq) {
|
||||||
pr_debug("irq: -> existing mapping on virq %d\n", virq);
|
pr_debug("-> existing mapping on virq %d\n", virq);
|
||||||
return virq;
|
return virq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +437,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
|
|||||||
if (virq <= 0)
|
if (virq <= 0)
|
||||||
virq = irq_alloc_desc_from(1, 0);
|
virq = irq_alloc_desc_from(1, 0);
|
||||||
if (virq <= 0) {
|
if (virq <= 0) {
|
||||||
pr_debug("irq: -> virq allocation failed\n");
|
pr_debug("-> virq allocation failed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,7 +447,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n",
|
pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
|
||||||
hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
|
hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
|
||||||
|
|
||||||
return virq;
|
return virq;
|
||||||
@@ -409,8 +476,8 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
|
|||||||
if (intsize > 0)
|
if (intsize > 0)
|
||||||
return intspec[0];
|
return intspec[0];
|
||||||
#endif
|
#endif
|
||||||
printk(KERN_WARNING "irq: no irq domain found for %s !\n",
|
pr_warning("no irq domain found for %s !\n",
|
||||||
controller->full_name);
|
controller->full_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,6 +627,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_domain *domain,
|
|||||||
*/
|
*/
|
||||||
return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);
|
return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_radix_revmap_lookup);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
|
* irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
|
||||||
@@ -584,6 +652,7 @@ void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq,
|
|||||||
mutex_unlock(&revmap_trees_mutex);
|
mutex_unlock(&revmap_trees_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_radix_revmap_insert);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* irq_linear_revmap() - Find a linux irq from a hw irq number.
|
* irq_linear_revmap() - Find a linux irq from a hw irq number.
|
||||||
@@ -617,6 +686,7 @@ unsigned int irq_linear_revmap(struct irq_domain *domain,
|
|||||||
|
|
||||||
return revmap[hwirq];
|
return revmap[hwirq];
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(irq_linear_revmap);
|
||||||
|
|
||||||
#ifdef CONFIG_IRQ_DOMAIN_DEBUG
|
#ifdef CONFIG_IRQ_DOMAIN_DEBUG
|
||||||
static int virq_debug_show(struct seq_file *m, void *private)
|
static int virq_debug_show(struct seq_file *m, void *private)
|
||||||
@@ -691,8 +761,8 @@ static int __init irq_debugfs_init(void)
|
|||||||
__initcall(irq_debugfs_init);
|
__initcall(irq_debugfs_init);
|
||||||
#endif /* CONFIG_IRQ_DOMAIN_DEBUG */
|
#endif /* CONFIG_IRQ_DOMAIN_DEBUG */
|
||||||
|
|
||||||
int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
|
static int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
|
||||||
irq_hw_number_t hwirq)
|
irq_hw_number_t hwirq)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user