Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b343c8be authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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.
parents 745914df a87487e6
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -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);
+88 −18
Original line number Original line Diff line number Diff line
#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,7 +476,7 @@ 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,7 +761,7 @@ 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;