summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c78
-rw-r--r--include/asm-sh/hw_irq.h12
2 files changed, 69 insertions, 21 deletions
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
index 481871fee1a..6ac018c15e0 100644
--- a/arch/sh/kernel/cpu/irq/intc.c
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -40,6 +40,9 @@ struct intc_handle_int {
struct intc_desc_int {
unsigned long *reg;
+#ifdef CONFIG_SMP
+ unsigned long *smp;
+#endif
unsigned int nr_reg;
struct intc_handle_int *prio;
unsigned int nr_prio;
@@ -48,6 +51,16 @@ struct intc_desc_int {
struct irq_chip chip;
};
+#ifdef CONFIG_SMP
+#define IS_SMP(x) x.smp
+#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
+#define SMP_NR(d, x) ((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
+#else
+#define IS_SMP(x) 0
+#define INTC_REG(d, x, c) (d->reg[(x)])
+#define SMP_NR(d, x) 1
+#endif
+
static unsigned int intc_prio_level[NR_IRQS]; /* for now */
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
@@ -177,11 +190,14 @@ static void (*intc_disable_fns[])(unsigned long addr,
static inline void _intc_enable(unsigned int irq, unsigned long handle)
{
struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long addr = d->reg[_INTC_ADDR_E(handle)];
+ unsigned long addr;
+ unsigned int cpu;
- intc_enable_fns[_INTC_MODE(handle)](addr, handle,
- intc_reg_fns[_INTC_FN(handle)],
- irq);
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu);
+ intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
}
static void intc_enable(unsigned int irq)
@@ -191,13 +207,16 @@ static void intc_enable(unsigned int irq)
static void intc_disable(unsigned int irq)
{
- struct intc_desc_int *desc = get_intc_desc(irq);
+ struct intc_desc_int *d = get_intc_desc(irq);
unsigned long handle = (unsigned long) get_irq_chip_data(irq);
- unsigned long addr = desc->reg[_INTC_ADDR_D(handle)];
+ unsigned long addr;
+ unsigned int cpu;
- intc_disable_fns[_INTC_MODE(handle)](addr, handle,
- intc_reg_fns[_INTC_FN(handle)],
- irq);
+ for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu);
+ intc_disable_fns[_INTC_MODE(handle)](addr, handle,intc_reg_fns\
+ [_INTC_FN(handle)], irq);
+ }
}
static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
@@ -276,7 +295,7 @@ static int intc_set_sense(unsigned int irq, unsigned int type)
ihp = intc_find_irq(d->sense, d->nr_sense, irq);
if (ihp) {
- addr = d->reg[_INTC_ADDR_E(ihp->handle)];
+ addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
}
return 0;
@@ -536,9 +555,26 @@ static void __init intc_register_irq(struct intc_desc *desc,
d->chip.mask(irq);
}
+static unsigned int __init save_reg(struct intc_desc_int *d,
+ unsigned int cnt,
+ unsigned long value,
+ unsigned int smp)
+{
+ if (value) {
+ d->reg[cnt] = value;
+#ifdef CONFIG_SMP
+ d->smp[cnt] = smp;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+
void __init register_intc_controller(struct intc_desc *desc)
{
- unsigned int i, k;
+ unsigned int i, k, smp;
struct intc_desc_int *d;
d = alloc_bootmem(sizeof(*d));
@@ -548,14 +584,16 @@ void __init register_intc_controller(struct intc_desc *desc)
d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0;
d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
+#ifdef CONFIG_SMP
+ d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
+#endif
k = 0;
if (desc->mask_regs) {
for (i = 0; i < desc->nr_mask_regs; i++) {
- if (desc->mask_regs[i].set_reg)
- d->reg[k++] = desc->mask_regs[i].set_reg;
- if (desc->mask_regs[i].clr_reg)
- d->reg[k++] = desc->mask_regs[i].clr_reg;
+ smp = IS_SMP(desc->mask_regs[i]);
+ k += save_reg(d, k, desc->mask_regs[i].set_reg, smp);
+ k += save_reg(d, k, desc->mask_regs[i].clr_reg, smp);
}
}
@@ -563,10 +601,9 @@ void __init register_intc_controller(struct intc_desc *desc)
d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
for (i = 0; i < desc->nr_prio_regs; i++) {
- if (desc->prio_regs[i].set_reg)
- d->reg[k++] = desc->prio_regs[i].set_reg;
- if (desc->prio_regs[i].clr_reg)
- d->reg[k++] = desc->prio_regs[i].clr_reg;
+ smp = IS_SMP(desc->prio_regs[i]);
+ k += save_reg(d, k, desc->prio_regs[i].set_reg, smp);
+ k += save_reg(d, k, desc->prio_regs[i].clr_reg, smp);
}
}
@@ -574,8 +611,7 @@ void __init register_intc_controller(struct intc_desc *desc)
d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
for (i = 0; i < desc->nr_sense_regs; i++) {
- if (desc->sense_regs[i].reg)
- d->reg[k++] = desc->sense_regs[i].reg;
+ k += save_reg(d, k, desc->sense_regs[i].reg, 0);
}
}
diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
index 96d97104050..cb0b6c9f702 100644
--- a/include/asm-sh/hw_irq.h
+++ b/include/asm-sh/hw_irq.h
@@ -50,11 +50,17 @@ struct intc_group {
struct intc_mask_reg {
unsigned long set_reg, clr_reg, reg_width;
intc_enum enum_ids[32];
+#ifdef CONFIG_SMP
+ unsigned long smp;
+#endif
};
struct intc_prio_reg {
unsigned long set_reg, clr_reg, reg_width, field_width;
intc_enum enum_ids[16];
+#ifdef CONFIG_SMP
+ unsigned long smp;
+#endif
};
struct intc_sense_reg {
@@ -62,6 +68,12 @@ struct intc_sense_reg {
intc_enum enum_ids[16];
};
+#ifdef CONFIG_SMP
+#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8)
+#else
+#define INTC_SMP(stride, nr)
+#endif
+
struct intc_desc {
struct intc_vect *vectors;
unsigned int nr_vectors;