Commit c1e30ad9 authored by Paul Mundt's avatar Paul Mundt

sh: intc: Support virtual mappings for IRQ subgroups.

Many interrupts that share a single mask source but are on different
hardware vectors will have an associated register tied to an INTEVT that
denotes the precise cause for the interrupt exception being triggered.

This introduces the concept of IRQ subgroups in the intc core, where
a virtual IRQ map is constructed for each of the pre-defined cause bits,
and a higher level chained handler takes control of the parent INTEVT.
This enables CPUs with heavily muxed IRQ vectors (especially across
disjoint blocks) to break things out in to a series of managed chained
handlers while being able to dynamically lookup and adopt the IRQs
created for them.

This is largely an opt-in interface, requiring CPUs to manually submit
IRQs for subgroup splitting, in addition to providing identifiers in
their enum maps that can be used for lazy lookup via the radix tree.
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 44629f57
...@@ -283,6 +283,8 @@ void __init init_IRQ(void) ...@@ -283,6 +283,8 @@ void __init init_IRQ(void)
if (sh_mv.mv_init_irq) if (sh_mv.mv_init_irq)
sh_mv.mv_init_irq(); sh_mv.mv_init_irq();
intc_finalize();
irq_ctx_init(smp_processor_id()); irq_ctx_init(smp_processor_id());
} }
......
This diff is collapsed.
...@@ -20,6 +20,12 @@ struct intc_group { ...@@ -20,6 +20,12 @@ struct intc_group {
#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } } #define INTC_GROUP(enum_id, ids...) { enum_id, { ids } }
struct intc_subgroup {
unsigned long reg, reg_width;
intc_enum parent_id;
intc_enum enum_ids[32];
};
struct intc_mask_reg { struct intc_mask_reg {
unsigned long set_reg, clr_reg, reg_width; unsigned long set_reg, clr_reg, reg_width;
intc_enum enum_ids[32]; intc_enum enum_ids[32];
...@@ -69,9 +75,12 @@ struct intc_hw_desc { ...@@ -69,9 +75,12 @@ struct intc_hw_desc {
unsigned int nr_sense_regs; unsigned int nr_sense_regs;
struct intc_mask_reg *ack_regs; struct intc_mask_reg *ack_regs;
unsigned int nr_ack_regs; unsigned int nr_ack_regs;
struct intc_subgroup *subgroups;
unsigned int nr_subgroups;
}; };
#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) #define _INTC_ARRAY(a) a, a == NULL ? 0 : sizeof(a)/sizeof(*a)
#define INTC_HW_DESC(vectors, groups, mask_regs, \ #define INTC_HW_DESC(vectors, groups, mask_regs, \
prio_regs, sense_regs, ack_regs) \ prio_regs, sense_regs, ack_regs) \
{ \ { \
...@@ -109,6 +118,7 @@ int __init register_intc_controller(struct intc_desc *desc); ...@@ -109,6 +118,7 @@ int __init register_intc_controller(struct intc_desc *desc);
void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs); void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
int intc_set_priority(unsigned int irq, unsigned int prio); int intc_set_priority(unsigned int irq, unsigned int prio);
unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id); unsigned int intc_irq_lookup(const char *chipname, intc_enum enum_id);
void intc_finalize(void);
#ifdef CONFIG_INTC_USERIMASK #ifdef CONFIG_INTC_USERIMASK
int register_intc_userimask(unsigned long addr); int register_intc_userimask(unsigned long addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment