forked from rubenslte/android_kernel_samsung_msm8226
irqdomain: Port system to new API
The following merge commit chose the irq_domain implementation from AU_LINUX_ANDROID_ICS.04.00.04.00.126 instead of the version in v3.4. commitf132c6cf77Merge:23016de3f6240fAuthor: Steve Muckle <smuckle@codeaurora.org> Date: Wed Jun 6 18:30:57 2012 -0700 Merge commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126' into msm-3.4 Since this version is inconsistent with the upstream, port the irq_domain framework to the version in v3.4 and makes all necessary changes to clients that are out of spec. Details of client ports are below. -Update the qpnp-int driver for revmap irq_domain API. The revmap irq_domain implementation introduces a reverse lookup scheme using a radix tree. This scheme is useful for controllers like qpnp-int that require a large range of hwirqs. -Bring the ARM GIC driver up to v3.4, being careful to port existing CAF changes. -Partially port the gpio-msm-common driver to the new irq_domain API. Enable the gpio-msm-common driver to work with the new irq_domain API using a linear revmap. It is not a full port since irq_domain is still only registered for Device Tree configurations. It should be registered even for legacy configurations. In addition, the irq_domains .map function should be setting all the fields currently done in msm_gpio_probe(). That's not currently possible since msm_gpio_probe is invoked unconditionally - even from Device Tree configurations. Finally, gpio-msm-common should be converted into a real platform_device so that probe() is invoked due to driver and device matching. Change-Id: I19fa50171bd244759fb6076e3cddc70896d8727b Signed-off-by: Michael Bohan <mbohan@codeaurora.org>
This commit is contained in:
+51
-70
@@ -64,9 +64,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 *);
|
||||
@@ -447,7 +445,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;
|
||||
}
|
||||
@@ -485,8 +483,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);
|
||||
@@ -520,10 +518,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());
|
||||
|
||||
@@ -566,23 +563,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);
|
||||
}
|
||||
|
||||
gic->max_irq = gic_irqs;
|
||||
|
||||
if (is_cpu_secure())
|
||||
@@ -833,11 +813,27 @@ 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_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,
|
||||
unsigned long *out_hwirq, unsigned int *out_type)
|
||||
{
|
||||
if (d->of_node != controller)
|
||||
return -EINVAL;
|
||||
@@ -854,26 +850,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d,
|
||||
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct irq_domain_ops gic_irq_domain_ops = {
|
||||
#ifdef CONFIG_OF
|
||||
.dt_translate = gic_irq_domain_dt_translate,
|
||||
#endif
|
||||
.map = gic_irq_domain_map,
|
||||
.xlate = gic_irq_domain_xlate,
|
||||
};
|
||||
|
||||
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, rc;
|
||||
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;
|
||||
@@ -881,8 +874,11 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
||||
gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
|
||||
gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
|
||||
if (WARN_ON(!gic->dist_base.percpu_base ||
|
||||
!gic->cpu_base.percpu_base))
|
||||
goto init_bases_err;
|
||||
!gic->cpu_base.percpu_base)) {
|
||||
free_percpu(gic->dist_base.percpu_base);
|
||||
free_percpu(gic->cpu_base.percpu_base);
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
unsigned long offset = percpu_offset * cpu_logical_map(cpu);
|
||||
@@ -906,13 +902,12 @@ 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;
|
||||
if (gic_nr == 0) {
|
||||
if ((irq_start & 31) > 0) {
|
||||
domain->hwirq_base = 16;
|
||||
if (irq_start != -1)
|
||||
irq_start = (irq_start & ~31) + 16;
|
||||
}
|
||||
if (gic_nr == 0 && (irq_start & 31) > 0) {
|
||||
hwirq_base = 16;
|
||||
if (irq_start != -1)
|
||||
irq_start = (irq_start & ~31) + 16;
|
||||
} else {
|
||||
hwirq_base = 32;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -925,33 +920,22 @@ 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->priv = gic;
|
||||
domain->ops = &gic_irq_domain_ops;
|
||||
rc = irq_domain_add(domain);
|
||||
if (rc) {
|
||||
WARN(1, "Unable to create irq_domain\n");
|
||||
goto init_bases_err;
|
||||
}
|
||||
irq_domain_register(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);
|
||||
gic_cpu_init(gic);
|
||||
gic_pm_init(gic);
|
||||
|
||||
return;
|
||||
|
||||
init_bases_err:
|
||||
free_percpu(gic->dist_base.percpu_base);
|
||||
free_percpu(gic->cpu_base.percpu_base);
|
||||
}
|
||||
|
||||
void __cpuinit gic_secondary_init(unsigned int gic_nr)
|
||||
@@ -1036,7 +1020,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;
|
||||
@@ -1050,9 +1033,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);
|
||||
|
||||
@@ -40,7 +40,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);
|
||||
@@ -56,7 +56,7 @@ static inline void gic_set_irq_secure(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);
|
||||
}
|
||||
void gic_set_irq_secure(unsigned int irq);
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,8 @@ int __init qpnpint_of_init(struct device_node *node,
|
||||
* Used by the PMIC Arbiter driver or equivalent to register
|
||||
* callbacks for interrupt events.
|
||||
*/
|
||||
int qpnpint_register_controller(unsigned int busno,
|
||||
int qpnpint_register_controller(struct device_node *node,
|
||||
struct spmi_controller *ctrl,
|
||||
struct qpnp_local_int *li_cb);
|
||||
|
||||
/**
|
||||
@@ -68,8 +69,11 @@ static inline int __init qpnpint_of_init(struct device_node *node,
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline int qpnpint_register_controller(unsigned int busno,
|
||||
struct qpnp_local_int *li_cb)
|
||||
|
||||
static inline int qpnpint_register_controller(struct device_node *node,
|
||||
struct spmi_controller *ctrl,
|
||||
struct qpnp_local_int *li_cb)
|
||||
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
|
||||
@@ -100,7 +100,7 @@ struct msm_gpio_dev {
|
||||
DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
|
||||
DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
|
||||
DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
|
||||
struct irq_domain domain;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(tlmm_lock);
|
||||
@@ -152,15 +152,14 @@ static int msm_gpio_direction_output(struct gpio_chip *chip,
|
||||
static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
|
||||
struct irq_domain *domain = &g_dev->domain;
|
||||
return domain->irq_base + (offset - chip->base);
|
||||
struct irq_domain *domain = g_dev->domain;
|
||||
return irq_linear_revmap(domain, offset - chip->base);
|
||||
}
|
||||
|
||||
static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
|
||||
{
|
||||
struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
|
||||
struct irq_domain *domain = &g_dev->domain;
|
||||
return irq - domain->irq_base;
|
||||
struct irq_data *irq_data = irq_get_irq_data(irq);
|
||||
return irq_data->hwirq;
|
||||
}
|
||||
#else
|
||||
static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
@@ -391,6 +390,7 @@ static struct irq_chip msm_gpio_irq_chip = {
|
||||
*/
|
||||
static struct lock_class_key msm_gpio_lock_class;
|
||||
|
||||
/* TODO: This should be a real platform_driver */
|
||||
static int __devinit msm_gpio_probe(void)
|
||||
{
|
||||
int i, irq, ret;
|
||||
@@ -573,12 +573,12 @@ int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
|
||||
EXPORT_SYMBOL(msm_gpio_install_direct_irq);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int msm_gpio_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 msm_gpio_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;
|
||||
@@ -593,32 +593,32 @@ static int msm_gpio_domain_dt_translate(struct irq_domain *d,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: this really should be doing all the things that msm_gpio_probe() does,
|
||||
* but since the msm_gpio_probe is called unconditionally for DT and non-DT
|
||||
* configs, we can't duplicate it here. This should be fixed.
|
||||
*/
|
||||
int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops msm_gpio_irq_domain_ops = {
|
||||
.dt_translate = msm_gpio_domain_dt_translate,
|
||||
.xlate = msm_gpio_irq_domain_xlate,
|
||||
.map = msm_gpio_irq_domain_map,
|
||||
};
|
||||
|
||||
int __init msm_gpio_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain = &msm_gpio.domain;
|
||||
int start;
|
||||
|
||||
start = irq_domain_find_free_range(0, NR_MSM_GPIOS);
|
||||
domain->irq_base = irq_alloc_descs(start, 0, NR_MSM_GPIOS,
|
||||
numa_node_id());
|
||||
if (IS_ERR_VALUE(domain->irq_base)) {
|
||||
WARN(1, "Cannot allocate irq_descs @ IRQ%d\n", start);
|
||||
return domain->irq_base;
|
||||
msm_gpio.domain = irq_domain_add_linear(node, NR_MSM_GPIOS,
|
||||
&msm_gpio_irq_domain_ops, &msm_gpio);
|
||||
if (!msm_gpio.domain) {
|
||||
WARN(1, "Cannot allocate irq_domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
domain->nr_irq = NR_MSM_GPIOS;
|
||||
domain->of_node = of_node_get(node);
|
||||
domain->priv = &msm_gpio;
|
||||
domain->ops = &msm_gpio_irq_domain_ops;
|
||||
irq_domain_add(domain);
|
||||
msm_gpio.gpio_chip.of_node = of_node_get(node);
|
||||
pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
+125
-143
@@ -31,8 +31,6 @@
|
||||
#include <asm/mach/irq.h>
|
||||
#include <mach/qpnp-int.h>
|
||||
|
||||
#define QPNPINT_MAX_BUSSES 1
|
||||
|
||||
/* 16 slave_ids, 256 per_ids per slave, and 8 ints per per_id */
|
||||
#define QPNPINT_NR_IRQS (16 * 256 * 8)
|
||||
|
||||
@@ -66,13 +64,18 @@ struct q_irq_data {
|
||||
|
||||
struct q_chip_data {
|
||||
int bus_nr;
|
||||
struct irq_domain domain;
|
||||
struct irq_domain *domain;
|
||||
struct qpnp_local_int cb;
|
||||
struct spmi_controller *spmi_ctrl;
|
||||
struct radix_tree_root per_tree;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static struct q_chip_data chip_data[QPNPINT_MAX_BUSSES] __read_mostly;
|
||||
static LIST_HEAD(qpnpint_chips);
|
||||
static DEFINE_MUTEX(qpnpint_chips_mutex);
|
||||
|
||||
#define QPNPINT_MAX_BUSSES 4
|
||||
struct q_chip_data *chip_lookup[QPNPINT_MAX_BUSSES];
|
||||
|
||||
/**
|
||||
* qpnpint_encode_hwirq - translate between qpnp_irq_spec and
|
||||
@@ -138,8 +141,7 @@ static void qpnpint_irq_mask(struct irq_data *d)
|
||||
if (chip_d->cb.mask) {
|
||||
rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
|
||||
if (rc)
|
||||
pr_err("%s: decode failed on hwirq %lu\n",
|
||||
__func__, d->hwirq);
|
||||
pr_err("decode failed on hwirq %lu\n", d->hwirq);
|
||||
else
|
||||
chip_d->cb.mask(chip_d->spmi_ctrl, &q_spec,
|
||||
irq_d->priv_d);
|
||||
@@ -150,8 +152,7 @@ static void qpnpint_irq_mask(struct irq_data *d)
|
||||
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
|
||||
(u8 *)&irq_d->mask_shift, 1);
|
||||
if (rc)
|
||||
pr_err("%s: spmi failure on irq %d\n",
|
||||
__func__, d->irq);
|
||||
pr_err("spmi failure on irq %d\n", d->irq);
|
||||
}
|
||||
|
||||
static void qpnpint_irq_mask_ack(struct irq_data *d)
|
||||
@@ -168,8 +169,7 @@ static void qpnpint_irq_mask_ack(struct irq_data *d)
|
||||
if (chip_d->cb.mask) {
|
||||
rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
|
||||
if (rc)
|
||||
pr_err("%s: decode failed on hwirq %lu\n",
|
||||
__func__, d->hwirq);
|
||||
pr_err("decode failed on hwirq %lu\n", d->hwirq);
|
||||
else
|
||||
chip_d->cb.mask(chip_d->spmi_ctrl, &q_spec,
|
||||
irq_d->priv_d);
|
||||
@@ -180,14 +180,12 @@ static void qpnpint_irq_mask_ack(struct irq_data *d)
|
||||
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
|
||||
&irq_d->mask_shift, 1);
|
||||
if (rc)
|
||||
pr_err("%s: spmi failure on irq %d\n",
|
||||
__func__, d->irq);
|
||||
pr_err("spmi failure on irq %d\n", d->irq);
|
||||
|
||||
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
|
||||
&irq_d->mask_shift, 1);
|
||||
if (rc)
|
||||
pr_err("%s: spmi failure on irq %d\n",
|
||||
__func__, d->irq);
|
||||
pr_err("spmi failure on irq %d\n", d->irq);
|
||||
}
|
||||
|
||||
static void qpnpint_irq_unmask(struct irq_data *d)
|
||||
@@ -203,8 +201,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
|
||||
if (chip_d->cb.unmask) {
|
||||
rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
|
||||
if (rc)
|
||||
pr_err("%s: decode failed on hwirq %lu\n",
|
||||
__func__, d->hwirq);
|
||||
pr_err("decode failed on hwirq %lu\n", d->hwirq);
|
||||
else
|
||||
chip_d->cb.unmask(chip_d->spmi_ctrl, &q_spec,
|
||||
irq_d->priv_d);
|
||||
@@ -214,8 +211,7 @@ static void qpnpint_irq_unmask(struct irq_data *d)
|
||||
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
|
||||
&irq_d->mask_shift, 1);
|
||||
if (rc)
|
||||
pr_err("%s: spmi failure on irq %d\n",
|
||||
__func__, d->irq);
|
||||
pr_err("spmi failure on irq %d\n", d->irq);
|
||||
}
|
||||
|
||||
static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
@@ -253,8 +249,7 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
|
||||
rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_SET_TYPE, &buf, 3);
|
||||
if (rc)
|
||||
pr_err("%s: spmi failure on irq %d\n",
|
||||
__func__, d->irq);
|
||||
pr_err("spmi failure on irq %d\n", d->irq);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -279,13 +274,16 @@ static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
|
||||
return rc;
|
||||
irq_d->spmi_slave = q_spec.slave;
|
||||
irq_d->spmi_offset = q_spec.per << 8;
|
||||
irq_d->per_d->use_count++;
|
||||
irq_d->chip_d = chip_d;
|
||||
|
||||
if (chip_d->cb.register_priv_data)
|
||||
rc = chip_d->cb.register_priv_data(chip_d->spmi_ctrl, &q_spec,
|
||||
&irq_d->priv_d);
|
||||
return rc;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
irq_d->per_d->use_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct q_irq_data *qpnpint_alloc_irq_data(
|
||||
@@ -307,8 +305,10 @@ static struct q_irq_data *qpnpint_alloc_irq_data(
|
||||
per_d = radix_tree_lookup(&chip_d->per_tree, (hwirq & ~0x7));
|
||||
if (!per_d) {
|
||||
per_d = kzalloc(sizeof(struct q_perip_data), GFP_KERNEL);
|
||||
if (!per_d)
|
||||
if (!per_d) {
|
||||
kfree(irq_d);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
radix_tree_insert(&chip_d->per_tree,
|
||||
(hwirq & ~0x7), per_d);
|
||||
}
|
||||
@@ -317,74 +317,6 @@ static struct q_irq_data *qpnpint_alloc_irq_data(
|
||||
return irq_d;
|
||||
}
|
||||
|
||||
static int qpnpint_register_int(uint32_t busno, unsigned long hwirq)
|
||||
{
|
||||
int irq, rc;
|
||||
struct irq_domain *domain;
|
||||
struct q_irq_data *irq_d;
|
||||
|
||||
pr_debug("busno = %u hwirq = %lu\n", busno, hwirq);
|
||||
|
||||
if (hwirq < 0 || hwirq >= 32768) {
|
||||
pr_err("%s: hwirq %lu out of qpnp interrupt bounds\n",
|
||||
__func__, hwirq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (busno < 0 || busno > QPNPINT_MAX_BUSSES) {
|
||||
pr_err("%s: invalid bus number %d\n", __func__, busno);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
domain = &chip_data[busno].domain;
|
||||
irq = irq_domain_to_irq(domain, hwirq);
|
||||
|
||||
rc = irq_alloc_desc_at(irq, numa_node_id());
|
||||
if (rc < 0) {
|
||||
if (rc != -EEXIST)
|
||||
pr_err("%s: failed to alloc irq at %d with "
|
||||
"rc %d\n", __func__, irq, rc);
|
||||
return rc;
|
||||
}
|
||||
irq_d = qpnpint_alloc_irq_data(&chip_data[busno], hwirq);
|
||||
if (IS_ERR(irq_d)) {
|
||||
pr_err("%s: failed to alloc irq data %d with "
|
||||
"rc %d\n", __func__, irq, rc);
|
||||
rc = PTR_ERR(irq_d);
|
||||
goto register_err_cleanup;
|
||||
}
|
||||
rc = qpnpint_init_irq_data(&chip_data[busno], irq_d, hwirq);
|
||||
if (rc) {
|
||||
pr_err("%s: failed to init irq data %d with "
|
||||
"rc %d\n", __func__, irq, rc);
|
||||
goto register_err_cleanup;
|
||||
}
|
||||
|
||||
irq_domain_register_irq(domain, hwirq);
|
||||
|
||||
irq_set_chip_and_handler(irq,
|
||||
&qpnpint_chip,
|
||||
handle_level_irq);
|
||||
irq_set_chip_data(irq, irq_d);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(irq);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
register_err_cleanup:
|
||||
irq_free_desc(irq);
|
||||
if (!IS_ERR(irq_d)) {
|
||||
if (irq_d->per_d->use_count == 1)
|
||||
kfree(irq_d->per_d);
|
||||
else
|
||||
irq_d->per_d->use_count--;
|
||||
kfree(irq_d);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
|
||||
struct device_node *controller,
|
||||
const u32 *intspec, unsigned int intsize,
|
||||
@@ -392,11 +324,10 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
|
||||
unsigned int *out_type)
|
||||
{
|
||||
struct qpnp_irq_spec addr;
|
||||
struct q_chip_data *chip_d = d->priv;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s: intspec[0] 0x%x intspec[1] 0x%x intspec[2] 0x%x\n",
|
||||
__func__, intspec[0], intspec[1], intspec[2]);
|
||||
pr_debug("intspec[0] 0x%x intspec[1] 0x%x intspec[2] 0x%x\n",
|
||||
intspec[0], intspec[1], intspec[2]);
|
||||
|
||||
if (d->of_node != controller)
|
||||
return -EINVAL;
|
||||
@@ -409,41 +340,102 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
|
||||
|
||||
ret = qpnpint_encode_hwirq(&addr);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: invalid intspec\n", __func__);
|
||||
pr_err("invalid intspec\n");
|
||||
return ret;
|
||||
}
|
||||
*out_hwirq = ret;
|
||||
*out_type = IRQ_TYPE_NONE;
|
||||
|
||||
/**
|
||||
* Register the interrupt if it's not already registered.
|
||||
* This implies that mapping a qpnp interrupt allocates
|
||||
* resources.
|
||||
*/
|
||||
ret = qpnpint_register_int(chip_d->bus_nr, *out_hwirq);
|
||||
if (ret && ret != -EEXIST) {
|
||||
pr_err("%s: Cannot register hwirq %lu\n", __func__, *out_hwirq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qpnpint_free_irq_data(struct q_irq_data *irq_d)
|
||||
{
|
||||
if (irq_d->per_d->use_count == 1)
|
||||
kfree(irq_d->per_d);
|
||||
else
|
||||
irq_d->per_d->use_count--;
|
||||
kfree(irq_d);
|
||||
}
|
||||
|
||||
static int qpnpint_irq_domain_map(struct irq_domain *d,
|
||||
unsigned int virq, irq_hw_number_t hwirq)
|
||||
{
|
||||
struct q_chip_data *chip_d = d->host_data;
|
||||
struct q_irq_data *irq_d;
|
||||
int rc;
|
||||
|
||||
pr_debug("hwirq = %lu\n", hwirq);
|
||||
|
||||
if (hwirq < 0 || hwirq >= 32768) {
|
||||
pr_err("hwirq %lu out of bounds\n", hwirq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq_radix_revmap_insert(d, virq, hwirq);
|
||||
|
||||
irq_d = qpnpint_alloc_irq_data(chip_d, hwirq);
|
||||
if (IS_ERR(irq_d)) {
|
||||
pr_err("failed to alloc irq data for hwirq %lu\n", hwirq);
|
||||
return PTR_ERR(irq_d);
|
||||
}
|
||||
|
||||
rc = qpnpint_init_irq_data(chip_d, irq_d, hwirq);
|
||||
if (rc) {
|
||||
pr_err("failed to init irq data for hwirq %lu\n", hwirq);
|
||||
goto map_err;
|
||||
}
|
||||
|
||||
irq_set_chip_and_handler(virq,
|
||||
&qpnpint_chip,
|
||||
handle_level_irq);
|
||||
irq_set_chip_data(virq, irq_d);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(virq);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
map_err:
|
||||
qpnpint_free_irq_data(irq_d);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void qpnpint_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
|
||||
{
|
||||
struct q_irq_data *irq_d = irq_get_chip_data(virq);
|
||||
|
||||
if (WARN_ON(!irq_d))
|
||||
return;
|
||||
|
||||
qpnpint_free_irq_data(irq_d);
|
||||
}
|
||||
|
||||
const struct irq_domain_ops qpnpint_irq_domain_ops = {
|
||||
.dt_translate = qpnpint_irq_domain_dt_translate,
|
||||
.map = qpnpint_irq_domain_map,
|
||||
.unmap = qpnpint_irq_domain_unmap,
|
||||
.xlate = qpnpint_irq_domain_dt_translate,
|
||||
};
|
||||
|
||||
int qpnpint_register_controller(unsigned int busno,
|
||||
int qpnpint_register_controller(struct device_node *node,
|
||||
struct spmi_controller *ctrl,
|
||||
struct qpnp_local_int *li_cb)
|
||||
{
|
||||
if (busno >= QPNPINT_MAX_BUSSES)
|
||||
return -EINVAL;
|
||||
chip_data[busno].cb = *li_cb;
|
||||
chip_data[busno].spmi_ctrl = spmi_busnum_to_ctrl(busno);
|
||||
if (!chip_data[busno].spmi_ctrl)
|
||||
return -ENOENT;
|
||||
struct q_chip_data *chip_d;
|
||||
|
||||
return 0;
|
||||
if (!node || !ctrl || ctrl->nr >= QPNPINT_MAX_BUSSES)
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(chip_d, &qpnpint_chips, list)
|
||||
if (node == chip_d->domain->of_node) {
|
||||
chip_d->cb = *li_cb;
|
||||
chip_d->spmi_ctrl = ctrl;
|
||||
chip_lookup[ctrl->nr] = chip_d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL(qpnpint_register_controller);
|
||||
|
||||
@@ -457,21 +449,18 @@ int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
|
||||
pr_debug("spec slave = %u per = %u irq = %u\n",
|
||||
spec->slave, spec->per, spec->irq);
|
||||
|
||||
if (!spec || !spmi_ctrl)
|
||||
return -EINVAL;
|
||||
|
||||
busno = spmi_ctrl->nr;
|
||||
if (busno >= QPNPINT_MAX_BUSSES)
|
||||
if (!spec || !spmi_ctrl || busno >= QPNPINT_MAX_BUSSES)
|
||||
return -EINVAL;
|
||||
|
||||
hwirq = qpnpint_encode_hwirq(spec);
|
||||
if (hwirq < 0) {
|
||||
pr_err("%s: invalid irq spec passed\n", __func__);
|
||||
pr_err("invalid irq spec passed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
domain = &chip_data[busno].domain;
|
||||
irq = irq_domain_to_irq(domain, hwirq);
|
||||
domain = chip_lookup[busno]->domain;
|
||||
irq = irq_radix_revmap_lookup(domain, hwirq);
|
||||
|
||||
generic_handle_irq(irq);
|
||||
|
||||
@@ -479,31 +468,24 @@ int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
|
||||
}
|
||||
EXPORT_SYMBOL(qpnpint_handle_irq);
|
||||
|
||||
/**
|
||||
* This assumes that there's a relationship between the order of the interrupt
|
||||
* controllers specified to of_irq_match() is the SPMI device topology. If
|
||||
* this ever turns out to be a bad assumption, then of_irq_init_cb_t should
|
||||
* be modified to pass a parameter to this function.
|
||||
*/
|
||||
static int qpnpint_cnt __initdata;
|
||||
|
||||
int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
struct q_chip_data *chip_d = &chip_data[qpnpint_cnt];
|
||||
struct irq_domain *domain = &chip_d->domain;
|
||||
struct q_chip_data *chip_d;
|
||||
|
||||
chip_d = kzalloc(sizeof(struct q_chip_data), GFP_KERNEL);
|
||||
if (!chip_d)
|
||||
return -ENOMEM;
|
||||
|
||||
chip_d->domain = irq_domain_add_tree(node,
|
||||
&qpnpint_irq_domain_ops, chip_d);
|
||||
if (!chip_d->domain) {
|
||||
pr_err("Unable to allocate irq_domain\n");
|
||||
kfree(chip_d);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_RADIX_TREE(&chip_d->per_tree, GFP_ATOMIC);
|
||||
|
||||
domain->irq_base = irq_domain_find_free_range(0, QPNPINT_NR_IRQS);
|
||||
domain->nr_irq = QPNPINT_NR_IRQS;
|
||||
domain->of_node = of_node_get(node);
|
||||
domain->priv = chip_d;
|
||||
domain->ops = &qpnpint_irq_domain_ops;
|
||||
irq_domain_add(domain);
|
||||
|
||||
pr_info("irq_base = %d\n", domain->irq_base);
|
||||
|
||||
qpnpint_cnt++;
|
||||
list_add(&chip_d->list, &qpnpint_chips);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -664,7 +664,14 @@ static int __devinit spmi_pmic_arb_probe(struct platform_device *pdev)
|
||||
goto err_add_controller;
|
||||
|
||||
/* Register the interrupt enable/disable functions */
|
||||
qpnpint_register_controller(cell_index, &spmi_pmic_arb_intr_cb);
|
||||
ret = qpnpint_register_controller(pmic_arb->controller.dev.of_node,
|
||||
&pmic_arb->controller,
|
||||
&spmi_pmic_arb_intr_cb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to register controller %d\n",
|
||||
cell_index);
|
||||
goto err_reg_controller;
|
||||
}
|
||||
|
||||
/* Register device(s) from the device tree */
|
||||
of_spmi_register_devices(&pmic_arb->controller);
|
||||
@@ -674,6 +681,8 @@ static int __devinit spmi_pmic_arb_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_controller:
|
||||
spmi_del_controller(&pmic_arb->controller);
|
||||
err_add_controller:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return ret;
|
||||
|
||||
+132
-60
@@ -9,106 +9,178 @@
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
#define _LINUX_IRQDOMAIN_H
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/radix-tree.h>
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN
|
||||
struct device_node;
|
||||
struct irq_domain;
|
||||
struct of_device_id;
|
||||
|
||||
/* Number of irqs reserved for a legacy isa controller */
|
||||
#define NUM_ISA_INTERRUPTS 16
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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
|
||||
* @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 {
|
||||
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 (*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);
|
||||
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;
|
||||
unsigned int irq_base;
|
||||
unsigned int nr_irq;
|
||||
unsigned int hwirq_base;
|
||||
struct list_head link;
|
||||
|
||||
/* 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;
|
||||
} linear;
|
||||
struct {
|
||||
unsigned int max_irq;
|
||||
} nomap;
|
||||
struct radix_tree_root tree;
|
||||
} revmap_data;
|
||||
const struct irq_domain_ops *ops;
|
||||
void *priv;
|
||||
void *host_data;
|
||||
irq_hw_number_t inval_irq;
|
||||
|
||||
/* Optional device node pointer */
|
||||
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)
|
||||
#ifdef CONFIG_IRQ_DOMAIN
|
||||
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,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data);
|
||||
struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
|
||||
unsigned int size,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data);
|
||||
struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
|
||||
unsigned int max_irq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data);
|
||||
struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
|
||||
const 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);
|
||||
|
||||
static inline struct irq_domain *irq_domain_add_legacy_isa(
|
||||
struct device_node *of_node,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
|
||||
#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 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);
|
||||
|
||||
extern int irq_domain_add(struct irq_domain *domain);
|
||||
extern void irq_domain_del(struct irq_domain *domain);
|
||||
extern void irq_domain_register(struct irq_domain *domain);
|
||||
extern void irq_domain_register_irq(struct irq_domain *domain, int hwirq);
|
||||
extern void irq_domain_unregister(struct irq_domain *domain);
|
||||
extern void irq_domain_unregister_irq(struct irq_domain *domain, int hwirq);
|
||||
extern int irq_domain_find_free_range(unsigned int from, unsigned int cnt);
|
||||
extern const struct irq_domain_ops irq_domain_simple_ops;
|
||||
|
||||
extern struct irq_domain_ops irq_domain_simple_ops;
|
||||
#endif /* CONFIG_IRQ_DOMAIN */
|
||||
/* 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_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
|
||||
extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
|
||||
#if defined(CONFIG_OF_IRQ)
|
||||
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 */
|
||||
|
||||
#else /* CONFIG_IRQ_DOMAIN */
|
||||
static inline void irq_dispose_mapping(unsigned int virq) { }
|
||||
#endif /* !CONFIG_IRQ_DOMAIN */
|
||||
|
||||
#endif /* _LINUX_IRQDOMAIN_H */
|
||||
|
||||
+700
-232
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user