summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/sys_dp264.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel/sys_dp264.c')
-rw-r--r--arch/alpha/kernel/sys_dp264.c96
1 files changed, 84 insertions, 12 deletions
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 7414b8cc2..63abc109f 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -35,6 +35,10 @@
/* Note mask bit is true for ENABLED irqs. */
static unsigned long cached_irq_mask;
+/* dp264 boards handle at max four CPUs */
+static unsigned long cpu_irq_affinity[4];
+
+spinlock_t dp264_irq_lock = SPIN_LOCK_UNLOCKED;
static void
tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable)
@@ -50,9 +54,14 @@ tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable)
mask0 = mask1 = mask2 = mask3 = mask;
maskB = mask | isa_enable;
if (bcpu == 0) mask0 = maskB;
- if (bcpu == 1) mask1 = maskB;
- if (bcpu == 2) mask2 = maskB;
- if (bcpu == 3) mask3 = maskB;
+ else if (bcpu == 1) mask1 = maskB;
+ else if (bcpu == 2) mask2 = maskB;
+ else if (bcpu == 3) mask3 = maskB;
+
+ mask0 &= cpu_irq_affinity[0];
+ mask1 &= cpu_irq_affinity[1];
+ mask2 &= cpu_irq_affinity[2];
+ mask3 &= cpu_irq_affinity[3];
dim0 = &cchip->dim0.csr;
dim1 = &cchip->dim1.csr;
@@ -73,10 +82,12 @@ tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable)
*dim2;
*dim3;
#else
- volatile unsigned long *dimB = &cchip->dim1.csr;
+ volatile unsigned long *dimB;
if (bcpu == 0) dimB = &cchip->dim0.csr;
- if (bcpu == 2) dimB = &cchip->dim2.csr;
- if (bcpu == 3) dimB = &cchip->dim3.csr;
+ else if (bcpu == 1) dimB = &cchip->dim1.csr;
+ else if (bcpu == 2) dimB = &cchip->dim2.csr;
+ else if (bcpu == 3) dimB = &cchip->dim3.csr;
+
*dimB = mask | isa_enable;
mb();
*dimB;
@@ -95,18 +106,22 @@ clipper_update_irq_hw(unsigned long mask)
tsunami_update_irq_hw(mask, 1UL << 55);
}
-static inline void
+static void
dp264_enable_irq(unsigned int irq)
{
+ spin_lock(&dp264_irq_lock);
cached_irq_mask |= 1UL << irq;
dp264_update_irq_hw(cached_irq_mask);
+ spin_unlock(&dp264_irq_lock);
}
static void
dp264_disable_irq(unsigned int irq)
{
+ spin_lock(&dp264_irq_lock);
cached_irq_mask &= ~(1UL << irq);
dp264_update_irq_hw(cached_irq_mask);
+ spin_unlock(&dp264_irq_lock);
}
static unsigned int
@@ -116,18 +131,29 @@ dp264_startup_irq(unsigned int irq)
return 0; /* never anything pending */
}
-static inline void
+static void
+dp264_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ dp264_enable_irq(irq);
+}
+
+static void
clipper_enable_irq(unsigned int irq)
{
+ spin_lock(&dp264_irq_lock);
cached_irq_mask |= 1UL << irq;
clipper_update_irq_hw(cached_irq_mask);
+ spin_unlock(&dp264_irq_lock);
}
static void
clipper_disable_irq(unsigned int irq)
{
+ spin_lock(&dp264_irq_lock);
cached_irq_mask &= ~(1UL << irq);
clipper_update_irq_hw(cached_irq_mask);
+ spin_unlock(&dp264_irq_lock);
}
static unsigned int
@@ -137,6 +163,47 @@ clipper_startup_irq(unsigned int irq)
return 0; /* never anything pending */
}
+static void
+clipper_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ clipper_enable_irq(irq);
+}
+
+static void
+cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
+{
+ int cpu;
+
+ for (cpu = 0; cpu < 4; cpu++) {
+ unsigned long aff = cpu_irq_affinity[cpu];
+ if (affinity & (1UL << cpu))
+ aff |= 1UL << irq;
+ else
+ aff &= ~(1UL << irq);
+ cpu_irq_affinity[cpu] = aff;
+ }
+
+}
+
+static void
+dp264_set_affinity(unsigned int irq, unsigned long affinity)
+{
+ spin_lock(&dp264_irq_lock);
+ cpu_set_irq_affinity(irq, affinity);
+ dp264_update_irq_hw(cached_irq_mask);
+ spin_unlock(&dp264_irq_lock);
+}
+
+static void
+clipper_set_affinity(unsigned int irq, unsigned long affinity)
+{
+ spin_lock(&dp264_irq_lock);
+ cpu_set_irq_affinity(irq, affinity);
+ clipper_update_irq_hw(cached_irq_mask);
+ spin_unlock(&dp264_irq_lock);
+}
+
static struct hw_interrupt_type dp264_irq_type = {
typename: "DP264",
startup: dp264_startup_irq,
@@ -144,7 +211,8 @@ static struct hw_interrupt_type dp264_irq_type = {
enable: dp264_enable_irq,
disable: dp264_disable_irq,
ack: dp264_disable_irq,
- end: dp264_enable_irq,
+ end: dp264_end_irq,
+ set_affinity: dp264_set_affinity,
};
static struct hw_interrupt_type clipper_irq_type = {
@@ -154,7 +222,8 @@ static struct hw_interrupt_type clipper_irq_type = {
enable: clipper_enable_irq,
disable: clipper_disable_irq,
ack: clipper_disable_irq,
- end: clipper_enable_irq,
+ end: clipper_end_irq,
+ set_affinity: clipper_set_affinity,
};
static void
@@ -249,6 +318,8 @@ init_tsunami_irqs(struct hw_interrupt_type * ops)
static void __init
dp264_init_irq(void)
{
+ int cpu;
+
outb(0, DMA1_RESET_REG);
outb(0, DMA2_RESET_REG);
outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
@@ -257,10 +328,12 @@ dp264_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = dp264_srm_device_interrupt;
+ /* this is single threaded by design so no need of any smp lock */
+ for (cpu = 0; cpu < 4; cpu++)
+ cpu_irq_affinity[cpu] = ~0UL;
dp264_update_irq_hw(0UL);
init_i8259a_irqs();
- init_rtc_irq();
init_tsunami_irqs(&dp264_irq_type);
}
@@ -278,7 +351,6 @@ clipper_init_irq(void)
clipper_update_irq_hw(0UL);
init_i8259a_irqs();
- init_rtc_irq();
init_tsunami_irqs(&clipper_irq_type);
}