Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 261119
b: refs/heads/master
c: 08a543a
h: refs/heads/master
i:
  261117: 8ebc865
  261115: 9ed3087
  261111: 716234e
  261103: 959ef31
  261087: d34b6dd
  261055: 5a29f76
  260991: f4b7d97
  260863: a1ab433
  260607: aabc8f9
  260095: f5fe194
v: v3
  • Loading branch information
Grant Likely committed Jul 28, 2011
1 parent 9799737 commit c7ba6ce
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 20 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5fd1a2ed0ec6fb5449c71a988cc15edb8671b3d0
refs/heads/master: 08a543ad33fc188650801bd36eed4ffe272643e1
1 change: 1 addition & 0 deletions trunk/arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1682,6 +1682,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.

Expand Down
5 changes: 0 additions & 5 deletions trunk/arch/arm/include/asm/prom.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
#include <asm/setup.h>
#include <asm/irq.h>

static inline void irq_dispose_mapping(unsigned int virq)
{
return;
}

extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
extern void arm_dt_memblock_reserve(void);

Expand Down
14 changes: 0 additions & 14 deletions trunk/arch/arm/kernel/devtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,3 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)

return mdesc_best;
}

/**
* 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);
6 changes: 6 additions & 0 deletions trunk/include/linux/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,18 @@ enum {
};

struct msi_desc;
struct irq_domain;

/**
* struct irq_data - per irq and irq chip data passed down to chip functions
* @irq: interrupt number
* @hwirq: hardware interrupt number, local to the interrupt domain
* @node: node index useful for balancing
* @state_use_accessors: status information for irq chip functions.
* Use accessor functions to deal with it
* @chip: low level interrupt hardware access
* @domain: Interrupt translation domain; responsible for mapping
* between hwirq number and linux irq number.
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
Expand All @@ -128,9 +132,11 @@ struct msi_desc;
*/
struct irq_data {
unsigned int irq;
unsigned long hwirq;
unsigned int node;
unsigned int state_use_accessors;
struct irq_chip *chip;
struct irq_domain *domain;
void *handler_data;
void *chip_data;
struct msi_desc *msi_desc;
Expand Down
81 changes: 81 additions & 0 deletions trunk/include/linux/irqdomain.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* irq_domain - IRQ translation domains
*
* Translation infrastructure between hw and linux irq numbers. This is
* helpful for interrupt controllers to implement mapping between hardware
* irq numbers and the Linux irq number space.
*
* irq_domains also have a hook for translating device tree interrupt
* 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.
*/
#ifndef _LINUX_IRQDOMAIN_H
#define _LINUX_IRQDOMAIN_H

#include <linux/irq.h>

#ifdef CONFIG_IRQ_DOMAIN
struct device_node;
struct irq_domain;

/**
* struct irq_domain_ops - Methods for irq_domain objects
* @to_irq: (optional) given a local hardware irq number, return the linux
* irq number. If to_irq is not implemented, then the irq_domain
* will use this translation: irq = (domain->irq_base + hwirq)
* @dt_translate: Given a device tree node and interrupt specifier, decode
* the hardware irq number and linux irq type value.
*/
struct irq_domain_ops {
unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);

#ifdef CONFIG_OF
int (*dt_translate)(struct irq_domain *d, struct device_node *node,
const u32 *intspec, unsigned int intsize,
unsigned long *out_hwirq, unsigned int *out_type);
#endif /* CONFIG_OF */
};

/**
* struct irq_domain - Hardware interrupt number translation object
* @list: Element in global irq_domain list.
* @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
* @ops: pointer to irq_domain methods
* @priv: private data pointer for use by owner. Not touched by irq_domain
* core code.
* @of_node: (optional) Pointer to device tree nodes associated with the
* irq_domain. Used when decoding device tree interrupt specifiers.
*/
struct irq_domain {
struct list_head list;
unsigned int irq_base;
unsigned int nr_irq;
const struct irq_domain_ops *ops;
void *priv;
struct device_node *of_node;
};

/**
* irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
*
* Returns the linux irq number associated with a hardware irq. By default,
* the mapping is irq == domain->irq_base + hwirq, but this mapping can
* be overridden if the irq_domain implements a .to_irq() hook.
*/
static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
unsigned long hwirq)
{
return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
}

extern void irq_domain_add(struct irq_domain *domain);
extern void irq_domain_del(struct irq_domain *domain);
#endif /* CONFIG_IRQ_DOMAIN */

#endif /* _LINUX_IRQDOMAIN_H */
4 changes: 4 additions & 0 deletions trunk/include/linux/of_irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,17 @@ 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);
extern int of_irq_to_resource_table(struct device_node *dev,
struct resource *res, int nr_irqs);
extern struct device_node *of_irq_find_parent(struct device_node *child);


#endif /* CONFIG_OF_IRQ */
#endif /* CONFIG_OF */
#endif /* __OF_IRQ_H */
4 changes: 4 additions & 0 deletions trunk/kernel/irq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ config IRQ_EDGE_EOI_HANDLER
config GENERIC_IRQ_CHIP
bool

# Generic irq_domain hw <--> linux irq number translation
config IRQ_DOMAIN
bool

# Support forced irq threading
config IRQ_FORCED_THREADING
bool
Expand Down
1 change: 1 addition & 0 deletions trunk/kernel/irq/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
obj-$(CONFIG_PM_SLEEP) += pm.o
122 changes: 122 additions & 0 deletions trunk/kernel/irq/irqdomain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>

static LIST_HEAD(irq_domain_list);
static DEFINE_MUTEX(irq_domain_mutex);

/**
* 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)
{
struct irq_data *d;
int hwirq;

/*
* 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.
*/
for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
if (d || 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->list, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);
}

/**
* 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;

mutex_lock(&irq_domain_mutex);
list_del(&domain->list);
mutex_unlock(&irq_domain_mutex);

/* Clear the irq_domain assignments */
for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
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, list) {
if (!domain->ops->dt_translate)
continue;
rc = domain->ops->dt_translate(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);
#endif /* CONFIG_OF_IRQ */

0 comments on commit c7ba6ce

Please sign in to comment.