summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-24 00:12:35 +0000
commit482368b1a8e45430672c58c9a42e7d2004367126 (patch)
treece2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /arch/alpha/kernel
parente4d0251c6f56ab2e191afb70f80f382793e23f74 (diff)
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r--arch/alpha/kernel/Makefile2
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c12
-rw-r--r--arch/alpha/kernel/core_mcpcia.c20
-rw-r--r--arch/alpha/kernel/core_polaris.c4
-rw-r--r--arch/alpha/kernel/core_pyxis.c105
-rw-r--r--arch/alpha/kernel/core_tsunami.c4
-rw-r--r--arch/alpha/kernel/entry.S2
-rw-r--r--arch/alpha/kernel/i8259.c95
-rw-r--r--arch/alpha/kernel/irq.c820
-rw-r--r--arch/alpha/kernel/irq_impl.h59
-rw-r--r--arch/alpha/kernel/pci.c6
-rw-r--r--arch/alpha/kernel/pci_iommu.c216
-rw-r--r--arch/alpha/kernel/process.c9
-rw-r--r--arch/alpha/kernel/proto.h11
-rw-r--r--arch/alpha/kernel/setup.c13
-rw-r--r--arch/alpha/kernel/smp.c32
-rw-r--r--arch/alpha/kernel/sys_alcor.c123
-rw-r--r--arch/alpha/kernel/sys_cabriolet.c105
-rw-r--r--arch/alpha/kernel/sys_dp264.c237
-rw-r--r--arch/alpha/kernel/sys_eb64p.c85
-rw-r--r--arch/alpha/kernel/sys_eiger.c93
-rw-r--r--arch/alpha/kernel/sys_jensen.c72
-rw-r--r--arch/alpha/kernel/sys_miata.c95
-rw-r--r--arch/alpha/kernel/sys_mikasa.c78
-rw-r--r--arch/alpha/kernel/sys_nautilus.c30
-rw-r--r--arch/alpha/kernel/sys_noritake.c102
-rw-r--r--arch/alpha/kernel/sys_rawhide.c109
-rw-r--r--arch/alpha/kernel/sys_ruffian.c188
-rw-r--r--arch/alpha/kernel/sys_rx164.c199
-rw-r--r--arch/alpha/kernel/sys_sable.c228
-rw-r--r--arch/alpha/kernel/sys_sio.c43
-rw-r--r--arch/alpha/kernel/sys_sx164.c109
-rw-r--r--arch/alpha/kernel/sys_takara.c91
-rw-r--r--arch/alpha/kernel/time.c76
34 files changed, 2022 insertions, 1451 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 7cf5dae80..fa9e06371 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -14,7 +14,7 @@
O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
- ptrace.o time.o semaphore.o
+ ptrace.o time.o semaphore.o i8259.o
OX_OBJS := alpha_ksyms.o
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 15c7afd8c..725dd4f51 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -36,6 +36,7 @@
extern struct hwrpb_struct *hwrpb;
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+extern spinlock_t kernel_flag;
/* these are C runtime functions with special calling conventions: */
extern void __divl (void);
@@ -51,6 +52,7 @@ EXPORT_SYMBOL(alpha_mv);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(perf_irq);
@@ -96,6 +98,13 @@ EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memsetw);
EXPORT_SYMBOL(__constant_c_memset);
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(pci_unmap_sg);
+
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(hwrpb);
@@ -158,13 +167,16 @@ EXPORT_SYMBOL_NOVERS(__rwsem_wake);
*/
#ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
EXPORT_SYMBOL(synchronize_irq);
EXPORT_SYMBOL(flush_tlb_all);
EXPORT_SYMBOL(flush_tlb_mm);
EXPORT_SYMBOL(flush_tlb_page);
EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(smp_imb);
EXPORT_SYMBOL(cpu_data);
EXPORT_SYMBOL(__cpu_number_map);
+EXPORT_SYMBOL(smp_num_cpus);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c
index 19ceb2241..ac97ce1fe 100644
--- a/arch/alpha/kernel/core_mcpcia.c
+++ b/arch/alpha/kernel/core_mcpcia.c
@@ -45,12 +45,6 @@
#define MCPCIA_MAX_HOSES 4
-/* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively. Durango adds
- PCI2 and PCI3 at MID 6 and 7 respectively. */
-
-#define hose2mid(h) ((h) + 4)
-
-
/*
* Given a bus, device, and function number, compute resulting
* configuration space address and setup the MCPCIA_HAXR2 register
@@ -98,7 +92,7 @@ conf_read(unsigned long addr, unsigned char type1,
struct pci_controler *hose)
{
unsigned long flags;
- unsigned long mid = hose2mid(hose->index);
+ unsigned long mid = MCPCIA_HOSE2MID(hose->index);
unsigned int stat0, value, temp, cpu;
cpu = smp_processor_id();
@@ -146,7 +140,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1,
struct pci_controler *hose)
{
unsigned long flags;
- unsigned long mid = hose2mid(hose->index);
+ unsigned long mid = MCPCIA_HOSE2MID(hose->index);
unsigned int stat0, temp, cpu;
cpu = smp_processor_id();
@@ -297,7 +291,7 @@ void
mcpcia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
{
wmb();
- BUG();
+ *(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0;
mb();
}
@@ -305,7 +299,7 @@ static int __init
mcpcia_probe_hose(int h)
{
int cpu = smp_processor_id();
- int mid = hose2mid(h);
+ int mid = MCPCIA_HOSE2MID(h);
unsigned int pci_rev;
/* Gotta be REAL careful. If hose is absent, we get an mcheck. */
@@ -340,7 +334,7 @@ mcpcia_new_hose(int h)
{
struct pci_controler *hose;
struct resource *io, *mem, *hae_mem;
- int mid = hose2mid(h);
+ int mid = MCPCIA_HOSE2MID(h);
hose = alloc_pci_controler();
io = alloc_resource();
@@ -387,7 +381,7 @@ mcpcia_pci_clr_err(int mid)
static void __init
mcpcia_startup_hose(struct pci_controler *hose)
{
- int mid = hose2mid(hose->index);
+ int mid = MCPCIA_HOSE2MID(hose->index);
unsigned int tmp;
mcpcia_pci_clr_err(mid);
@@ -578,7 +572,7 @@ mcpcia_machine_check(unsigned long vector, unsigned long la_ptr,
error was on? */
struct pci_controler *hose;
for (hose = hose_head; hose; hose = hose->next)
- mcpcia_pci_clr_err(hose2mid(hose->index));
+ mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index));
break;
}
case 1:
diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c
index 0164a3e15..f76ac0654 100644
--- a/arch/alpha/kernel/core_polaris.c
+++ b/arch/alpha/kernel/core_polaris.c
@@ -107,7 +107,7 @@ polaris_read_config_word(struct pci_dev *dev, int where, u16 *value)
return PCIBIOS_SUCCESSFUL;
}
-static int
+int
polaris_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
unsigned long pci_addr;
@@ -150,7 +150,7 @@ polaris_write_config_word(struct pci_dev *dev, int where, u16 value)
return PCIBIOS_SUCCESSFUL;
}
-static int
+int
polaris_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
unsigned long pci_addr;
diff --git a/arch/alpha/kernel/core_pyxis.c b/arch/alpha/kernel/core_pyxis.c
index cd81d5b91..80ee8ba7f 100644
--- a/arch/alpha/kernel/core_pyxis.c
+++ b/arch/alpha/kernel/core_pyxis.c
@@ -23,6 +23,7 @@
#include <asm/system.h>
#include "proto.h"
+#include "irq_impl.h"
#include "pci_impl.h"
@@ -286,6 +287,108 @@ struct pci_ops pyxis_pci_ops =
write_dword: pyxis_write_config_dword
};
+/* Note mask bit is true for ENABLED irqs. */
+static unsigned long cached_irq_mask;
+
+static inline void
+pyxis_update_irq_hw(unsigned long mask)
+{
+ *(vulp)PYXIS_INT_MASK = mask;
+ mb();
+ *(vulp)PYXIS_INT_MASK;
+}
+
+static inline void
+pyxis_enable_irq(unsigned int irq)
+{
+ pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+}
+
+static inline void
+pyxis_disable_irq(unsigned int irq)
+{
+ pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+}
+
+static unsigned int
+pyxis_startup_irq(unsigned int irq)
+{
+ pyxis_enable_irq(irq);
+ return 0;
+}
+
+static void
+pyxis_mask_and_ack_irq(unsigned int irq)
+{
+ unsigned long bit = 1UL << (irq - 16);
+ unsigned long mask = cached_irq_mask &= ~bit;
+
+ /* Disable the interrupt. */
+ *(vulp)PYXIS_INT_MASK = mask;
+ wmb();
+ /* Ack PYXIS PCI interrupt. */
+ *(vulp)PYXIS_INT_REQ = bit;
+ mb();
+ /* Re-read to force both writes. */
+ *(vulp)PYXIS_INT_MASK;
+}
+
+static struct hw_interrupt_type pyxis_irq_type = {
+ typename: "PYXIS",
+ startup: pyxis_startup_irq,
+ shutdown: pyxis_disable_irq,
+ enable: pyxis_enable_irq,
+ disable: pyxis_disable_irq,
+ ack: pyxis_mask_and_ack_irq,
+ end: pyxis_enable_irq,
+};
+
+void
+pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long pld;
+ unsigned int i;
+
+ /* Read the interrupt summary register of PYXIS */
+ pld = *(vulp)PYXIS_INT_REQ;
+ pld &= cached_irq_mask;
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 7)
+ isa_device_interrupt(vector, regs);
+ else
+ handle_irq(16+i, regs);
+ }
+}
+
+void __init
+init_pyxis_irqs(unsigned long ignore_mask)
+{
+ long i;
+
+ *(vulp)PYXIS_INT_MASK = 0; /* disable all */
+ *(vulp)PYXIS_INT_REQ = -1; /* flush all */
+ mb();
+
+ /* Send -INTA pulses to clear any pending interrupts ...*/
+ *(vuip) PYXIS_IACK_SC;
+
+ for (i = 16; i < 48; ++i) {
+ if ((ignore_mask >> i) & 1)
+ continue;
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &pyxis_irq_type;
+ }
+
+ setup_irq(16+7, &isa_cascade_irqaction);
+}
+
void
pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
{
@@ -342,7 +445,7 @@ pyxis_broken_pci_tbi(struct pci_controler *hose,
__restore_flags(flags);
}
-static void
+static void __init
pyxis_enable_broken_tbi(struct pci_iommu_arena *arena)
{
void *page;
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index 0ad001b94..5fa112173 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -224,7 +224,7 @@ tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
}
#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
-static long
+static long __init
tsunami_probe_read(volatile unsigned long *vaddr)
{
long dont_care, probe_result;
@@ -246,7 +246,7 @@ tsunami_probe_read(volatile unsigned long *vaddr)
return probe_result;
}
-static long
+static long __init
tsunami_probe_write(volatile unsigned long *vaddr)
{
long true_contents, probe_result = 1;
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index cd8ce5c67..5f1a6f59a 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -573,7 +573,7 @@ entSys:
.align 3
ret_from_sys_call:
cmovne $26,0,$19 /* $19 = 0 => non-restartable */
- ldq $3,TASK_PROCESSOR($8)
+ ldl $3,TASK_PROCESSOR($8)
lda $4,softirq_state
sll $3,5,$3
addq $3,$4,$4
diff --git a/arch/alpha/kernel/i8259.c b/arch/alpha/kernel/i8259.c
new file mode 100644
index 000000000..ad545b98e
--- /dev/null
+++ b/arch/alpha/kernel/i8259.c
@@ -0,0 +1,95 @@
+/*
+ * linux/arch/alpha/kernel/i8259.c
+ *
+ * This is the 'legacy' 8259A Programmable Interrupt Controller,
+ * present in the majority of PC/AT boxes.
+ *
+ * Started hacking from linux-2.3.30pre6/arch/i386/kernel/i8259.c.
+ */
+
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+
+#include "proto.h"
+#include "irq_impl.h"
+
+
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned int cached_irq_mask = 0xffff;
+
+static inline void
+i8259_update_irq_hw(unsigned int irq, unsigned long mask)
+{
+ int port = 0x21;
+ if (irq & 8) mask >>= 8;
+ if (irq & 8) port = 0xA1;
+ outb(mask, port);
+}
+
+inline void
+i8259a_enable_irq(unsigned int irq)
+{
+ i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+}
+
+inline void
+i8259a_disable_irq(unsigned int irq)
+{
+ i8259_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+}
+
+void
+i8259a_mask_and_ack_irq(unsigned int irq)
+{
+ i8259a_disable_irq(irq);
+
+ /* Ack the interrupt making it the lowest priority. */
+ if (irq >= 8) {
+ outb(0xE0 | (irq - 8), 0xa0); /* ack the slave */
+ irq = 2;
+ }
+ outb(0xE0 | irq, 0x20); /* ack the master */
+}
+
+unsigned int
+i8259a_startup_irq(unsigned int irq)
+{
+ i8259a_enable_irq(irq);
+ return 0; /* never anything pending */
+}
+
+struct hw_interrupt_type i8259a_irq_type = {
+ typename: "XT-PIC",
+ startup: i8259a_startup_irq,
+ shutdown: i8259a_disable_irq,
+ enable: i8259a_enable_irq,
+ disable: i8259a_disable_irq,
+ ack: i8259a_mask_and_ack_irq,
+ end: i8259a_enable_irq,
+};
+
+void __init
+init_i8259a_irqs(void)
+{
+ static struct irqaction cascade = {
+ handler: no_action,
+ name: "cascade",
+ };
+
+ long i;
+
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+ outb(0xff, 0xA1); /* mask all of 8259A-2 */
+
+ for (i = 0; i < 16; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &i8259a_irq_type;
+ }
+
+ setup_irq(2, &cascade);
+}
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index bae28a6a4..3d593acf3 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -17,32 +17,29 @@
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
-#include <linux/interrupt.h>
#include <linux/malloc.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/dma.h>
#include <asm/bitops.h>
#include <asm/machvec.h>
#include "proto.h"
+#include "irq_impl.h"
#define vulp volatile unsigned long *
#define vuip volatile unsigned int *
/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it lives
in the per-cpu structure for cache reasons. */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
int __local_irq_count;
int __local_bh_count;
-#endif
-
-#if NR_IRQS > 128
-# error Unable to handle more than 128 irq levels.
+unsigned long __irq_attempt[NR_IRQS];
#endif
#ifdef CONFIG_ALPHA_GENERIC
@@ -51,39 +48,13 @@ int __local_bh_count;
#define ACTUAL_NR_IRQS NR_IRQS
#endif
-/* Reserved interrupts. These must NEVER be requested by any driver!
- IRQ 2 used by hw cascade */
-#define IS_RESERVED_IRQ(irq) ((irq)==2)
-
-
/*
- * Shadow-copy of masked interrupts.
+ * Performance counter hook. A module can override this to
+ * do something useful.
*/
-unsigned long _alpha_irq_masks[2] = { ~0UL, ~0UL };
-
-/*
- * The ack_irq routine used by 80% of the systems.
- */
-
-void
-common_ack_irq(unsigned long irq)
-{
- if (irq < 16) {
- /* Ack the interrupt making it the lowest priority */
- /* First the slave .. */
- if (irq > 7) {
- outb(0xE0 | (irq - 8), 0xa0);
- irq = 2;
- }
- /* .. then the master */
- outb(0xE0 | irq, 0x20);
- }
-}
-
-
-
-static void dummy_perf(unsigned long vector, struct pt_regs *regs)
+static void
+dummy_perf(unsigned long vector, struct pt_regs *regs)
{
printk(KERN_CRIT "Performance counter interrupt!\n");
}
@@ -94,7 +65,9 @@ void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
* Dispatch device interrupts.
*/
-/* Handle ISA interrupt via the PICs. */
+/*
+ * Handle ISA interrupt via the PICs.
+ */
#if defined(CONFIG_ALPHA_GENERIC)
# define IACK_SC alpha_mv.iack_sc
@@ -112,15 +85,12 @@ void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
# define IACK_SC POLARIS_IACK_SC
#elif defined(CONFIG_ALPHA_IRONGATE)
# define IACK_SC IRONGATE_IACK_SC
-#else
- /* This is bogus but necessary to get it to compile on all platforms. */
-# define IACK_SC 1L
#endif
+#if defined(IACK_SC)
void
-isa_device_interrupt(unsigned long vector, struct pt_regs * regs)
+isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
-#if 1
/*
* Generate a PCI interrupt acknowledge cycle. The PIC will
* respond with the interrupt vector of the highest priority
@@ -135,8 +105,13 @@ isa_device_interrupt(unsigned long vector, struct pt_regs * regs)
return;
}
}
- handle_irq(j, j, regs);
-#else
+ handle_irq(j, regs);
+}
+#endif
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
+void
+isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs)
+{
unsigned long pic;
/*
@@ -153,131 +128,341 @@ isa_device_interrupt(unsigned long vector, struct pt_regs * regs)
* write only. This is not true.
*/
pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */
- pic &= ~alpha_irq_mask; /* apply mask */
pic &= 0xFFFB; /* mask out cascade & hibits */
while (pic) {
int j = ffz(~pic);
pic &= pic - 1;
- handle_irq(j, j, regs);
+ handle_irq(j, regs);
}
+}
#endif
+
+/*
+ * Handle interrupts from the SRM, assuming no additional weirdness.
+ */
+
+static inline void
+srm_enable_irq(unsigned int irq)
+{
+ cserve_ena(irq - 16);
+}
+
+static void
+srm_disable_irq(unsigned int irq)
+{
+ cserve_dis(irq - 16);
}
-/* Handle interrupts from the SRM, assuming no additional weirdness. */
+static unsigned int
+srm_startup_irq(unsigned int irq)
+{
+ srm_enable_irq(irq);
+ return 0;
+}
+
+static struct hw_interrupt_type srm_irq_type = {
+ typename: "SRM",
+ startup: srm_startup_irq,
+ shutdown: srm_disable_irq,
+ enable: srm_enable_irq,
+ disable: srm_disable_irq,
+ ack: srm_disable_irq,
+ end: srm_enable_irq,
+};
void
srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq, ack;
+ int irq = (vector - 0x800) >> 4;
+ handle_irq(irq, regs);
+}
- ack = irq = (vector - 0x800) >> 4;
- handle_irq(irq, ack, regs);
+void __init
+init_srm_irqs(long max, unsigned long ignore_mask)
+{
+ long i;
+
+ for (i = 16; i < max; ++i) {
+ if (i < 64 && ((ignore_mask >> i) & 1))
+ continue;
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &srm_irq_type;
+ }
}
+/*
+ * The not-handled irq handler.
+ */
+
+static void
+noirq_enable_disable(unsigned int irq)
+{
+}
+
+static unsigned int
+noirq_startup(unsigned int irq)
+{
+ return 0;
+}
+
+static void
+noirq_ack(unsigned int irq)
+{
+ printk(KERN_CRIT "Unexpected IRQ %u\n", irq);
+}
+
+static struct hw_interrupt_type no_irq_type = {
+ typename: "none",
+ startup: noirq_startup,
+ shutdown: noirq_enable_disable,
+ enable: noirq_enable_disable,
+ disable: noirq_enable_disable,
+ ack: noirq_ack,
+ end: noirq_enable_disable,
+};
/*
- * Initial irq handlers.
+ * The special RTC interrupt type. The interrupt itself was
+ * processed by PALcode, and comes in via entInt vector 1.
*/
-static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
-spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = {0,} };
+static struct hw_interrupt_type rtc_irq_type = {
+ typename: "RTC",
+ startup: noirq_startup,
+ shutdown: noirq_enable_disable,
+ enable: noirq_enable_disable,
+ disable: noirq_enable_disable,
+ ack: noirq_enable_disable,
+ end: noirq_enable_disable,
+};
+void __init
+init_rtc_irq(void)
+{
+ irq_desc[RTC_IRQ].status = IRQ_DISABLED;
+ irq_desc[RTC_IRQ].handler = &rtc_irq_type;
+}
-static inline void
-mask_irq(unsigned long irq)
+/*
+ * Special irq handlers.
+ */
+
+void
+no_action(int cpl, void *dev_id, struct pt_regs *regs)
{
- set_bit(irq, _alpha_irq_masks);
- alpha_mv.update_irq_hw(irq, alpha_irq_mask, 0);
}
-static inline void
-unmask_irq(unsigned long irq)
+/*
+ * Common irq handlers.
+ */
+
+struct irqaction isa_cascade_irqaction = {
+ handler: no_action,
+ name: "isa-cascade"
+};
+
+struct irqaction timer_cascade_irqaction = {
+ handler: no_action,
+ name: "timer-cascade"
+};
+
+struct irqaction halt_switch_irqaction = {
+ handler: no_action,
+ name: "halt-switch"
+};
+
+
+spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+ [0 ... NR_IRQS-1] = { 0, &no_irq_type, }
+};
+
+int
+handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+ struct irqaction *action)
{
- clear_bit(irq, _alpha_irq_masks);
- alpha_mv.update_irq_hw(irq, alpha_irq_mask, 1);
+ int status, cpu = smp_processor_id();
+ unsigned long ipl;
+
+ kstat.irqs[cpu][irq]++;
+ irq_enter(cpu, irq);
+
+ status = 1; /* Force the "do bottom halves" bit */
+ ipl = rdps() & 7;
+
+ do {
+ unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0);
+ if (newipl != ipl) {
+ swpipl(newipl);
+ ipl = newipl;
+ }
+
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ if (ipl == 0)
+ __cli();
+
+ irq_exit(cpu, irq);
+
+ return status;
}
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
void
-disable_irq_nosync(unsigned int irq_nr)
+disable_irq_nosync(unsigned int irq)
{
unsigned long flags;
- save_and_cli(flags);
- mask_irq(irq_nr);
- restore_flags(flags);
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ if (!irq_desc[irq].depth++) {
+ irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].handler->disable(irq);
+ }
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
}
+/*
+ * Synchronous version of the above, making sure the IRQ is
+ * no longer running on any other IRQ..
+ */
void
-disable_irq(unsigned int irq_nr)
+disable_irq(unsigned int irq)
{
- /* This works non-SMP, and SMP until we write code to distribute
- interrupts to more that cpu 0. */
- disable_irq_nosync(irq_nr);
+ disable_irq_nosync(irq);
+
+ if (!local_irq_count(smp_processor_id())) {
+ do {
+ barrier();
+ } while (irq_desc[irq].status & IRQ_INPROGRESS);
+ }
}
void
-enable_irq(unsigned int irq_nr)
+enable_irq(unsigned int irq)
{
unsigned long flags;
- save_and_cli(flags);
- unmask_irq(irq_nr);
- restore_flags(flags);
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ switch (irq_desc[irq].depth) {
+ case 1:
+ {
+ unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
+ irq_desc[irq].status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ irq_desc[irq].status = status | IRQ_REPLAY;
+
+ /* ??? We can't re-send on (most?) alpha hw.
+ hw_resend_irq(irq_desc[irq].handler,irq); */
+ }
+ irq_desc[irq].handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ irq_desc[irq].depth--;
+ break;
+ case 0:
+ printk(KERN_ERR "enable_irq() unbalanced from %p\n",
+ __builtin_return_address(0));
+ }
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
}
int
-check_irq(unsigned int irq)
+setup_irq(unsigned int irq, struct irqaction * new)
{
- return irq_desc[irq].action ? -EBUSY : 0;
+ int shared = 0;
+ struct irqaction *old, **p;
+ unsigned long flags;
+
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&irq_controller_lock,flags);
+ p = &irq_desc[irq].action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ irq_desc[irq].depth = 0;
+ irq_desc[irq].status &= ~IRQ_DISABLED;
+ irq_desc[irq].handler->startup(irq);
+ }
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
+ return 0;
}
int
request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char * devname, void *dev_id)
{
- int shared = 0;
- struct irqaction * action, **p;
- unsigned long flags;
+ int retval;
+ struct irqaction * action;
if (irq >= ACTUAL_NR_IRQS)
return -EINVAL;
- if (IS_RESERVED_IRQ(irq))
- return -EINVAL;
if (!handler)
return -EINVAL;
- p = &irq_desc[irq].action;
- action = *p;
- if (action) {
- /* Can't share interrupts unless both agree to */
- if (!(action->flags & irqflags & SA_SHIRQ))
- return -EBUSY;
-
- /* Can't share interrupts unless both are same type */
- if ((action->flags ^ irqflags) & SA_INTERRUPT)
- return -EBUSY;
-
- /* Add new interrupt at end of irq queue */
- do {
- p = &action->next;
- action = *p;
- } while (action);
- shared = 1;
+#if 1
+ /*
+ * Sanity-check: shared interrupts should REALLY pass in
+ * a real dev-ID, otherwise we'll have trouble later trying
+ * to figure out which interrupt is which (messes up the
+ * interrupt freeing logic etc).
+ */
+ if ((irqflags & SA_SHIRQ) && !dev_id) {
+ printk(KERN_ERR
+ "Bad boy: %s (at %p) called us without a dev_id!\n",
+ devname, __builtin_return_address(0));
}
+#endif
- action = &timer_irq;
- if (irq != TIMER_IRQ) {
- action = (struct irqaction *)
+ action = (struct irqaction *)
kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- }
if (!action)
return -ENOMEM;
- if (irqflags & SA_SAMPLE_RANDOM)
- rand_initialize_irq(irq);
-
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
@@ -285,56 +470,66 @@ request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
action->next = NULL;
action->dev_id = dev_id;
- save_and_cli(flags);
- *p = action;
-
- if (!shared)
- unmask_irq(irq);
-
- restore_flags(flags);
- return 0;
+ retval = setup_irq(irq, action);
+ if (retval)
+ kfree(action);
+ return retval;
}
-
+
void
free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction * action, **p;
+ struct irqaction **p;
unsigned long flags;
if (irq >= ACTUAL_NR_IRQS) {
- printk("Trying to free IRQ%d\n",irq);
- return;
- }
- if (IS_RESERVED_IRQ(irq)) {
- printk("Trying to free reserved IRQ %d\n", irq);
+ printk(KERN_CRIT "Trying to free IRQ%d\n", irq);
return;
}
- for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
- if (action->dev_id != dev_id)
- continue;
- /* Found it - now free it */
- save_and_cli(flags);
- *p = action->next;
- if (!irq_desc[irq].action)
- mask_irq(irq);
- restore_flags(flags);
- kfree(action);
+ spin_lock_irqsave(&irq_controller_lock,flags);
+ p = &irq_desc[irq].action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found - now remove it from the list of entries. */
+ *pp = action->next;
+ if (!irq_desc[irq].action) {
+ irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].handler->shutdown(irq);
+ }
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
+
+ /* Wait to make sure it's not being used on
+ another CPU. */
+ while (irq_desc[irq].status & IRQ_INPROGRESS)
+ barrier();
+ kfree(action);
+ return;
+ }
+ printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&irq_controller_lock,flags);
return;
}
- printk("Trying to free free IRQ%d\n",irq);
}
int get_irq_list(char *buf)
{
- int i;
+ int i, j;
struct irqaction * action;
char *p = buf;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
p += sprintf(p, " ");
for (i = 0; i < smp_num_cpus; i++)
p += sprintf(p, "CPU%d ", i);
+ for (i = 0; i < smp_num_cpus; i++)
+ p += sprintf(p, "TRY%d ", i);
*p++ = '\n';
#endif
@@ -343,16 +538,17 @@ int get_irq_list(char *buf)
if (!action)
continue;
p += sprintf(p, "%3d: ",i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
p += sprintf(p, "%10u ", kstat_irqs(i));
#else
- {
- int j;
- for (j = 0; j < smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- kstat.irqs[cpu_logical_map(j)][i]);
- }
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10lu ",
+ irq_attempt(cpu_logical_map(j), i));
#endif
+ p += sprintf(p, " %14s", irq_desc[i].handler->typename);
p += sprintf(p, " %c%s",
(action->flags & SA_INTERRUPT)?'+':' ',
action->name);
@@ -364,10 +560,17 @@ int get_irq_list(char *buf)
}
*p++ = '\n';
}
+#if CONFIG_SMP
+ p += sprintf(p, "LOC: ");
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10lu ",
+ cpu_data[cpu_logical_map(j)].smp_local_irq_count);
+ p += sprintf(p, "\n");
+#endif
return p - buf;
}
-#ifdef __SMP__
+#ifdef CONFIG_SMP
/* Who has global_irq_lock. */
int global_irq_holder = NO_PROC_ID;
@@ -527,7 +730,7 @@ __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%p)\n",
+ printk(KERN_ERR "global_restore_flags: %08lx (%p)\n",
flags, __builtin_return_address(0));
}
}
@@ -603,141 +806,195 @@ synchronize_irq(void)
}
#endif
}
-#endif /* __SMP__ */
-
-static void
-unexpected_irq(int irq, struct pt_regs * regs)
-{
-#if 0
-#if 1
- printk("device_interrupt: unexpected interrupt %d\n", irq);
-#else
- struct irqaction *action;
- int i;
-
- printk("IO device interrupt, irq = %d\n", irq);
- printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
- printk("Expecting: ");
- for (i = 0; i < ACTUAL_NR_IRQS; i++)
- if ((action = irq_desc[i].action))
- while (action->handler) {
- printk("[%s:%d] ", action->name, i);
- action = action->next;
- }
- printk("\n");
-#endif
-#endif
-
-#if defined(CONFIG_ALPHA_JENSEN)
- /* ??? Is all this just debugging, or are the inb's and outb's
- necessary to make things work? */
- printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
- inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
- outb(0x0c, 0x3fc);
- outb(0x0c, 0x2fc);
- outb(0,0x61);
- outb(0,0x461);
-#endif
-}
+#endif /* CONFIG_SMP */
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
void
-handle_irq(int irq, int ack, struct pt_regs * regs)
-{
- struct irqaction * action;
+handle_irq(int irq, struct pt_regs * regs)
+{
+ /*
+ * We ack quickly, we don't want the irq controller
+ * thinking we're snobs just because some other CPU has
+ * disabled global interrupts (we have already done the
+ * INT_ACK cycles, it's too late to try to pretend to the
+ * controller that we aren't taking the interrupt).
+ *
+ * 0 return value means that this irq is already being
+ * handled by some other CPU. (or is disabled)
+ */
int cpu = smp_processor_id();
+ irq_desc_t *desc;
+ struct irqaction * action;
+ unsigned int status;
if ((unsigned) irq > ACTUAL_NR_IRQS) {
- printk("device_interrupt: illegal interrupt %d\n", irq);
+ printk(KERN_CRIT "device_interrupt: illegal interrupt %d\n",
+ irq);
return;
}
-#if 0
- /* A useful bit of code to find out if an interrupt is going wild. */
- {
- static unsigned int last_msg, last_cc;
- static int last_irq, count;
- unsigned int cc;
-
- __asm __volatile("rpcc %0" : "=r"(cc));
- ++count;
- if (cc - last_msg > 150000000 || irq != last_irq) {
- printk("handle_irq: irq %d count %d cc %u @ %p\n",
- irq, count, cc-last_cc, regs->pc);
- count = 0;
- last_msg = cc;
- last_irq = irq;
- }
- last_cc = cc;
- }
-#endif
+ irq_attempt(cpu, irq)++;
+ desc = irq_desc + irq;
+ spin_lock_irq(&irq_controller_lock); /* mask also the RTC */
+ desc->handler->ack(irq);
- irq_enter(cpu, irq);
- kstat.irqs[cpu][irq] += 1;
- action = irq_desc[irq].action;
+ /*
+ * REPLAY is when Linux resends an IRQ that was dropped earlier.
+ * WAITING is used by probe to mark irqs that are being tested.
+ */
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+ status |= IRQ_PENDING; /* we _want_ to handle it */
/*
- * For normal interrupts, we mask it out, and then ACK it.
- * This way another (more timing-critical) interrupt can
- * come through while we're doing this one.
- *
- * Note! An irq without a handler gets masked and acked, but
- * never unmasked. The autoirq stuff depends on this (it looks
- * at the masks before and after doing the probing).
+ * If the IRQ is disabled for whatever reason, we cannot
+ * use the action we have.
*/
- if (ack >= 0) {
- mask_irq(ack);
- alpha_mv.ack_irq(ack);
+ action = NULL;
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ action = desc->action;
+ status &= ~IRQ_PENDING; /* we commit to handling */
+ status |= IRQ_INPROGRESS; /* we are handling it */
}
- if (action) {
- if (action->flags & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- do {
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while (action);
- if (ack >= 0)
- unmask_irq(ack);
- } else {
- unexpected_irq(irq, regs);
+ desc->status = status;
+ spin_unlock(&irq_controller_lock);
+
+ /*
+ * If there is no IRQ handler or it was disabled, exit early.
+ * Since we set PENDING, if another processor is handling
+ * a different instance of this same irq, the other processor
+ * will take care of it.
+ */
+ if (!action)
+ return;
+
+ /*
+ * Edge triggered interrupts need to remember pending events.
+ * This applies to any hw interrupts that allow a second
+ * instance of the same irq to arrive while we are in do_IRQ
+ * or in the handler. But the code here only handles the _second_
+ * instance of the irq, not the third or fourth. So it is mostly
+ * useful for irq hardware that does not mask cleanly in an
+ * SMP environment.
+ */
+ for (;;) {
+ handle_IRQ_event(irq, regs, action);
+ spin_lock(&irq_controller_lock);
+
+ if (!(desc->status & IRQ_PENDING)
+ || (desc->status & IRQ_LEVEL))
+ break;
+ desc->status &= ~IRQ_PENDING;
+ spin_unlock(&irq_controller_lock);
}
- irq_exit(cpu, irq);
+ desc->status &= ~IRQ_INPROGRESS;
+ if (!(desc->status & IRQ_DISABLED))
+ desc->handler->end(irq);
+ spin_unlock(&irq_controller_lock);
}
-
/*
- * Start listening for interrupts..
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
*/
-
unsigned long
probe_irq_on(void)
{
- struct irqaction * action;
- unsigned long irqs = 0;
+ int i;
unsigned long delay;
- unsigned int i;
-
- /* Handle only the first 64 IRQs here. This is enough for
- [E]ISA, which is the only thing that needs probing anyway. */
- for (i = (ACTUAL_NR_IRQS - 1) & 63; i > 0; i--) {
- if (!(PROBE_MASK & (1UL << i))) {
- continue;
- }
- action = irq_desc[i].action;
- if (!action) {
- enable_irq(i);
- irqs |= (1UL << i);
+ unsigned long val;
+
+ /* Something may have generated an irq long ago and we want to
+ flush such a longstanding irq before considering it as spurious. */
+ spin_lock_irq(&irq_controller_lock);
+ for (i = NR_IRQS-1; i >= 0; i--)
+ if (!irq_desc[i].action)
+ if(irq_desc[i].handler->startup(i))
+ irq_desc[i].status |= IRQ_PENDING;
+ spin_unlock_irq(&irq_controller_lock);
+
+ /* Wait for longstanding interrupts to trigger. */
+ for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+ /* about 20ms delay */ synchronize_irq();
+
+ /* enable any unassigned irqs (we must startup again here because
+ if a longstanding irq happened in the previous stage, it may have
+ masked itself) first, enable any unassigned irqs. */
+ spin_lock_irq(&irq_controller_lock);
+ for (i = NR_IRQS-1; i >= 0; i--) {
+ if (!irq_desc[i].action) {
+ irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
+ if(irq_desc[i].handler->startup(i))
+ irq_desc[i].status |= IRQ_PENDING;
}
}
+ spin_unlock_irq(&irq_controller_lock);
+
+ /*
+ * Wait for spurious interrupts to trigger
+ */
+ for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+ /* about 100ms delay */ synchronize_irq();
/*
- * Wait about 100ms for spurious interrupts to mask themselves
- * out again...
+ * Now filter out any obviously spurious interrupts
*/
- for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
- barrier();
+ val = 0;
+ spin_lock_irq(&irq_controller_lock);
+ for (i=0; i<NR_IRQS; i++) {
+ unsigned int status = irq_desc[i].status;
- /* Now filter out any obviously spurious interrupts. */
- return irqs & ~alpha_irq_mask;
+ if (!(status & IRQ_AUTODETECT))
+ continue;
+
+ /* It triggered already - consider it spurious. */
+ if (!(status & IRQ_WAITING)) {
+ irq_desc[i].status = status & ~IRQ_AUTODETECT;
+ irq_desc[i].handler->shutdown(i);
+ continue;
+ }
+
+ if (i < 64)
+ val |= 1 << i;
+ }
+ spin_unlock_irq(&irq_controller_lock);
+
+ return val;
+}
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+ int i;
+ unsigned int mask;
+
+ mask = 0;
+ spin_lock_irq(&irq_controller_lock);
+ for (i = 0; i < 16; i++) {
+ unsigned int status = irq_desc[i].status;
+
+ if (!(status & IRQ_AUTODETECT))
+ continue;
+
+ if (!(status & IRQ_WAITING))
+ mask |= 1 << i;
+
+ irq_desc[i].status = status & ~IRQ_AUTODETECT;
+ irq_desc[i].handler->shutdown(i);
+ }
+ spin_unlock_irq(&irq_controller_lock);
+
+ return mask & val;
}
/*
@@ -747,19 +1004,32 @@ probe_irq_on(void)
*/
int
-probe_irq_off(unsigned long irqs)
+probe_irq_off(unsigned long val)
{
- int i;
-
- /* Handle only the first 64 IRQs here. This is enough for
- [E]ISA, which is the only thing that needs probing anyway. */
- irqs &= alpha_irq_mask;
- if (!irqs)
- return 0;
- i = ffz(~irqs);
- if (irqs != (1UL << i))
- i = -i;
- return i;
+ int i, irq_found, nr_irqs;
+
+ nr_irqs = 0;
+ irq_found = 0;
+ spin_lock_irq(&irq_controller_lock);
+ for (i=0; i<NR_IRQS; i++) {
+ unsigned int status = irq_desc[i].status;
+
+ if (!(status & IRQ_AUTODETECT))
+ continue;
+
+ if (!(status & IRQ_WAITING)) {
+ if (!nr_irqs)
+ irq_found = i;
+ nr_irqs++;
+ }
+ irq_desc[i].status = status & ~IRQ_AUTODETECT;
+ irq_desc[i].handler->shutdown(i);
+ }
+ spin_unlock_irq(&irq_controller_lock);
+
+ if (nr_irqs > 1)
+ irq_found = -irq_found;
+ return irq_found;
}
@@ -774,15 +1044,21 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
{
switch (type) {
case 0:
-#ifdef __SMP__
+#ifdef CONFIG_SMP
handle_ipi(&regs);
return;
#else
- printk("Interprocessor interrupt? You must be kidding\n");
+ printk(KERN_CRIT "Interprocessor interrupt? "
+ "You must be kidding!\n");
#endif
break;
case 1:
- handle_irq(RTC_IRQ, -1, &regs);
+#ifdef CONFIG_SMP
+ cpu_data[smp_processor_id()].smp_local_irq_count++;
+ smp_percpu_timer_interrupt(&regs);
+ if (smp_processor_id() == smp_boot_cpuid)
+#endif
+ handle_irq(RTC_IRQ, &regs);
return;
case 2:
alpha_mv.machine_check(vector, la_ptr, &regs);
@@ -794,12 +1070,22 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
perf_irq(vector, &regs);
return;
default:
- printk("Hardware intr %ld %lx? Huh?\n", type, vector);
+ printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n",
+ type, vector);
}
printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
}
void __init
+common_init_isa_dma(void)
+{
+ outb(0, DMA1_RESET_REG);
+ outb(0, DMA2_RESET_REG);
+ outb(0, DMA1_CLR_MASK_REG);
+ outb(0, DMA2_CLR_MASK_REG);
+}
+
+void __init
init_IRQ(void)
{
wrent(entInt, 0);
@@ -817,7 +1103,7 @@ init_IRQ(void)
#define MCHK_K_OS_BUGCHECK 0x008A
#define MCHK_K_PAL_BUGCHECK 0x0090
-#ifndef __SMP__
+#ifndef CONFIG_SMP
struct mcheck_info __mcheck_info;
#endif
diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h
new file mode 100644
index 000000000..ff8067a00
--- /dev/null
+++ b/arch/alpha/kernel/irq_impl.h
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/alpha/kernel/irq_impl.h
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1998, 2000 Richard Henderson
+ *
+ * This file contains declarations and inline functions for interfacing
+ * with the IRQ handling routines in irq.c.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+
+#define RTC_IRQ 8
+
+extern void isa_device_interrupt(unsigned long, struct pt_regs *);
+extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *);
+extern void srm_device_interrupt(unsigned long, struct pt_regs *);
+extern void pyxis_device_interrupt(unsigned long, struct pt_regs *);
+
+extern struct irqaction isa_cascade_irqaction;
+extern struct irqaction timer_cascade_irqaction;
+extern struct irqaction halt_switch_irqaction;
+
+extern void init_srm_irqs(long, unsigned long);
+extern void init_pyxis_irqs(unsigned long);
+extern void init_rtc_irq(void);
+
+extern void common_init_isa_dma(void);
+
+extern void i8259a_enable_irq(unsigned int);
+extern void i8259a_disable_irq(unsigned int);
+extern void i8259a_mask_and_ack_irq(unsigned int);
+extern unsigned int i8259a_startup_irq(unsigned int);
+extern struct hw_interrupt_type i8259a_irq_type;
+extern void init_i8259a_irqs(void);
+
+extern void no_action(int cpl, void *dev_id, struct pt_regs *regs);
+extern void handle_irq(int irq, struct pt_regs * regs);
+
+static inline void
+alpha_do_profile(unsigned long pc)
+{
+ if (prof_buffer && current->pid) {
+ extern char _stext;
+
+ pc -= (unsigned long) &_stext;
+ pc >>= prof_shift;
+ /*
+ * Don't ignore out-of-bounds PC values silently,
+ * put them into the last histogram slot, so if
+ * present, they will show up as a sharp peak.
+ */
+ if (pc > prof_len - 1)
+ pc = prof_len - 1;
+ atomic_inc((atomic_t *)&prof_buffer[pc]);
+ }
+}
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index b62179b8d..12e3f0df9 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -109,7 +109,7 @@ struct pci_fixup pcibios_fixups[] __initdata = {
void
pcibios_align_resource(void *data, struct resource *res, unsigned long size)
{
- struct pci_dev * dev = data;
+ struct pci_dev *dev = data;
unsigned long alignto;
unsigned long start = res->start;
@@ -325,10 +325,10 @@ pcibios_fixup_pbus_ranges(struct pci_bus * bus,
ranges->mem_end -= bus->resource[1]->start;
}
-int __init
+int
pcibios_enable_device(struct pci_dev *dev)
{
- /* Not needed, since we enable all devices at startup. */
+ /* Nothing to do, since we enable all devices at startup. */
return 0;
}
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 8faa66901..72ce8bcb6 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -16,7 +16,6 @@
#define DEBUG_ALLOC 0
-
#if DEBUG_ALLOC > 0
# define DBGA(args...) printk(KERN_DEBUG ##args)
#else
@@ -122,10 +121,10 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n)
/* Map a single buffer of the indicate size for PCI DMA in streaming
mode. The 32-bit PCI bus mastering address to use is returned.
Once the device is given the dma address, the device owns this memory
- until either pci_unmap_single or pci_sync_single is performed. */
+ until either pci_unmap_single or pci_dma_sync_single is performed. */
dma_addr_t
-pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size)
+pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
{
struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
@@ -173,10 +172,6 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size)
ret = arena->dma_base + dma_ofs * PAGE_SIZE;
ret += (unsigned long)cpu_addr & ~PAGE_MASK;
- /* ??? This shouldn't have been needed, since the entries
- we've just modified were not in the iommu tlb. */
- alpha_mv.mv_pci_tbi(hose, ret, ret + size - 1);
-
DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n",
cpu_addr, size, npages, ret, __builtin_return_address(0));
@@ -191,7 +186,7 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size)
wrote there. */
void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size)
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction)
{
struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
struct pci_iommu_arena *arena;
@@ -239,11 +234,12 @@ void *
pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
{
void *cpu_addr;
+ long order = get_order(size);
- cpu_addr = kmalloc(size, GFP_ATOMIC);
+ cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order);
if (! cpu_addr) {
- printk(KERN_INFO "dma_alloc_consistent: "
- "kmalloc failed from %p\n",
+ printk(KERN_INFO "pci_alloc_consistent: "
+ "get_free_pages failed from %p\n",
__builtin_return_address(0));
/* ??? Really atomic allocation? Otherwise we could play
with vmalloc and sg if we can't find contiguous memory. */
@@ -251,13 +247,13 @@ pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
}
memset(cpu_addr, 0, size);
- *dma_addrp = pci_map_single(pdev, cpu_addr, size);
+ *dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL);
if (*dma_addrp == 0) {
- kfree_s(cpu_addr, size);
+ free_pages((unsigned long)cpu_addr, order);
return NULL;
}
- DBGA2("dma_alloc_consistent: %lx -> [%p,%x] from %p\n",
+ DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n",
size, cpu_addr, *dma_addrp, __builtin_return_address(0));
return cpu_addr;
@@ -274,33 +270,34 @@ void
pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr,
dma_addr_t dma_addr)
{
- pci_unmap_single(pdev, dma_addr, size);
- kfree_s(cpu_addr, size);
+ pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)cpu_addr, get_order(size));
- DBGA2("dma_free_consistent: [%x,%lx] from %p\n",
+ DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
dma_addr, size, __builtin_return_address(0));
}
/* Classify the elements of the scatterlist. Write dma_address
of each element with:
- 0 : Not mergable.
- 1 : Followers all physically adjacent.
- [23]: Followers all virtually adjacent.
- -1 : Not leader.
+ 0 : Followers all physically adjacent.
+ 1 : Followers all virtually adjacent.
+ -1 : Not leader, physically adjacent to previous.
+ -2 : Not leader, virtually adjacent to previous.
Write dma_length of each leader with the combined lengths of
the mergable followers. */
static inline void
-sg_classify(struct scatterlist *sg, struct scatterlist *end)
+sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
{
unsigned long next_vaddr;
struct scatterlist *leader;
+ long leader_flag, leader_length;
leader = sg;
- leader->dma_address = 0;
- leader->dma_length = leader->length;
- next_vaddr = (unsigned long)leader->address + leader->length;
+ leader_flag = 0;
+ leader_length = leader->length;
+ next_vaddr = (unsigned long)leader->address + leader_length;
for (++sg; sg < end; ++sg) {
unsigned long addr, len;
@@ -309,20 +306,24 @@ sg_classify(struct scatterlist *sg, struct scatterlist *end)
if (next_vaddr == addr) {
sg->dma_address = -1;
- leader->dma_address |= 1;
- leader->dma_length += len;
- } else if (((next_vaddr | addr) & ~PAGE_MASK) == 0) {
- sg->dma_address = -1;
- leader->dma_address |= 2;
- leader->dma_length += len;
+ leader_length += len;
+ } else if (((next_vaddr | addr) & ~PAGE_MASK) == 0 && virt_ok) {
+ sg->dma_address = -2;
+ leader_flag = 1;
+ leader_length += len;
} else {
+ leader->dma_address = leader_flag;
+ leader->dma_length = leader_length;
leader = sg;
- leader->dma_address = 0;
- leader->dma_length = len;
+ leader_flag = 0;
+ leader_length = len;
}
next_vaddr = addr + len;
}
+
+ leader->dma_address = leader_flag;
+ leader->dma_length = leader_length;
}
/* Given a scatterlist leader, choose an allocation method and fill
@@ -334,21 +335,21 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end,
dma_addr_t max_dma)
{
unsigned long paddr = virt_to_phys(leader->address);
- unsigned long size = leader->dma_length;
+ long size = leader->dma_length;
struct scatterlist *sg;
unsigned long *ptes;
long npages, dma_ofs, i;
/* If everything is physically contiguous, and the addresses
fall into the direct-map window, use it. */
- if (leader->dma_address < 2
+ if (leader->dma_address == 0
&& paddr + size + __direct_map_base - 1 <= max_dma
&& paddr + size <= __direct_map_size) {
out->dma_address = paddr + __direct_map_base;
out->dma_length = size;
- DBGA2("sg_fill: [%p,%lx] -> direct %x\n",
- leader->address, size, out->dma_address);
+ DBGA(" sg_fill: [%p,%lx] -> direct %x\n",
+ leader->address, size, out->dma_address);
return 0;
}
@@ -365,101 +366,119 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end,
out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
out->dma_length = size;
- DBGA("sg_fill: [%p,%lx] -> sg %x\n",
- leader->address, size, out->dma_address);
+ DBGA(" sg_fill: [%p,%lx] -> sg %x np %ld\n",
+ leader->address, size, out->dma_address, npages);
ptes = &arena->ptes[dma_ofs];
sg = leader;
- do {
- paddr = virt_to_phys(sg->address);
- npages = calc_npages((paddr & ~PAGE_MASK) + sg->length);
-
- DBGA(" (%ld) [%p,%x]\n",
- sg - leader, sg->address, sg->length);
+ if (0 && leader->dma_address == 0) {
+ /* All physically contiguous. We already have the
+ length, all we need is to fill in the ptes. */
- paddr &= PAGE_MASK;
+ paddr = virt_to_phys(sg->address) & PAGE_MASK;
for (i = 0; i < npages; ++i, paddr += PAGE_SIZE)
*ptes++ = mk_iommu_pte(paddr);
- ++sg;
- } while (sg < end && sg->dma_address == -1);
+#if DEBUG_ALLOC > 0
+ DBGA(" (0) [%p,%x] np %ld\n",
+ sg->address, sg->length, npages);
+ for (++sg; sg < end && (int) sg->dma_address < 0; ++sg)
+ DBGA(" (%ld) [%p,%x] cont\n",
+ sg - leader, sg->address, sg->length);
+#endif
+ } else {
+ /* All virtually contiguous. We need to find the
+ length of each physically contiguous subsegment
+ to fill in the ptes. */
+ do {
+ struct scatterlist *last_sg = sg;
+
+ size = sg->length;
+ paddr = virt_to_phys(sg->address);
+
+ while (sg+1 < end && (int) sg[1].dma_address == -1) {
+ size += sg[1].length;
+ sg++;
+ }
+
+ npages = calc_npages((paddr & ~PAGE_MASK) + size);
+
+ paddr &= PAGE_MASK;
+ for (i = 0; i < npages; ++i, paddr += PAGE_SIZE)
+ *ptes++ = mk_iommu_pte(paddr);
+
+#if DEBUG_ALLOC > 0
+ DBGA(" (%ld) [%p,%x] np %ld\n",
+ last_sg - leader, last_sg->address,
+ last_sg->length, npages);
+ while (++last_sg <= sg) {
+ DBGA(" (%ld) [%p,%x] cont\n",
+ last_sg - leader, last_sg->address,
+ last_sg->length);
+ }
+#endif
+ } while (++sg < end && (int) sg->dma_address < 0);
+ }
return 1;
}
-/* TODO: Only use the iommu when it helps. Non-mergable scatterlist
- entries might as well use direct mappings. */
-
int
-pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
+pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
{
struct scatterlist *start, *end, *out;
struct pci_controler *hose;
struct pci_iommu_arena *arena;
- dma_addr_t max_dma, fstart, fend;
-
- /* If pci_tbi is not available, we must not be able to control
- an iommu. Direct map everything, no merging. */
- if (! alpha_mv.mv_pci_tbi) {
- for (end = sg + nents; sg < end; ++sg) {
- sg->dma_address = virt_to_bus(sg->address);
- sg->dma_length = sg->length;
- }
- return nents;
- }
+ dma_addr_t max_dma;
/* Fast path single entry scatterlists. */
if (nents == 1) {
sg->dma_length = sg->length;
sg->dma_address
- = pci_map_single(pdev, sg->address, sg->length);
+ = pci_map_single(pdev, sg->address, sg->length, direction);
return sg->dma_address != 0;
}
- hose = pdev ? pdev->sysdata : pci_isa_hose;
- max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
- arena = hose->sg_pci;
- if (!arena || arena->dma_base + arena->size > max_dma)
- arena = hose->sg_isa;
start = sg;
end = sg + nents;
- fstart = -1;
- fend = 0;
-
+
/* First, prepare information about the entries. */
- sg_classify(sg, end);
+ sg_classify(sg, end, alpha_mv.mv_pci_tbi != 0);
+
+ /* Second, figure out where we're going to map things. */
+ if (alpha_mv.mv_pci_tbi) {
+ hose = pdev ? pdev->sysdata : pci_isa_hose;
+ max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
+ arena = hose->sg_pci;
+ if (!arena || arena->dma_base + arena->size > max_dma)
+ arena = hose->sg_isa;
+ } else {
+ max_dma = -1;
+ arena = NULL;
+ hose = NULL;
+ }
- /* Second, iterate over the scatterlist leaders and allocate
+ /* Third, iterate over the scatterlist leaders and allocate
dma space as needed. */
for (out = sg; sg < end; ++sg) {
int ret;
- if (sg->dma_address == -1)
+ if ((int) sg->dma_address < 0)
continue;
ret = sg_fill(sg, end, out, arena, max_dma);
if (ret < 0)
goto error;
- else if (ret > 0) {
- dma_addr_t ts, te;
-
- ts = out->dma_address;
- te = ts + out->dma_length - 1;
- if (fstart > ts)
- fstart = ts;
- if (fend < te)
- fend = te;
- }
out++;
}
- /* ??? This shouldn't have been needed, since the entries
- we've just modified were not in the iommu tlb. */
- if (fend)
- alpha_mv.mv_pci_tbi(hose, fstart, fend);
+ /* Mark the end of the list for pci_unmap_sg. */
+ if (out < end)
+ out->dma_length = 0;
if (out - start == 0)
printk(KERN_INFO "pci_map_sg failed: no entries?\n");
+ DBGA("pci_map_sg: %ld entries\n", out - start);
return out - start;
@@ -470,7 +489,7 @@ error:
/* Some allocation failed while mapping the scatterlist
entries. Unmap them now. */
if (out > start)
- pci_unmap_sg(pdev, start, out - start);
+ pci_unmap_sg(pdev, start, out - start, direction);
return 0;
}
@@ -480,7 +499,7 @@ error:
above. */
void
-pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
+pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
{
struct pci_controler *hose;
struct pci_iommu_arena *arena;
@@ -496,23 +515,30 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
arena = hose->sg_pci;
if (!arena || arena->dma_base + arena->size > max_dma)
arena = hose->sg_isa;
+
fstart = -1;
fend = 0;
-
for (end = sg + nents; sg < end; ++sg) {
unsigned long addr, size;
addr = sg->dma_address;
size = sg->dma_length;
+ if (!size)
+ break;
+
if (addr >= __direct_map_base
&& addr < __direct_map_base + __direct_map_size) {
/* Nothing to do. */
- DBGA2("pci_unmap_sg: direct [%lx,%lx]\n", addr, size);
+ DBGA(" (%ld) direct [%lx,%lx]\n",
+ sg - end + nents, addr, size);
} else {
long npages, ofs;
dma_addr_t tend;
+ DBGA(" (%ld) sg [%lx,%lx]\n",
+ sg - end + nents, addr, size);
+
npages = calc_npages((addr & ~PAGE_MASK) + size);
ofs = (addr - arena->dma_base) >> PAGE_SHIFT;
iommu_arena_free(arena, ofs, npages);
@@ -522,10 +548,10 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
fstart = addr;
if (fend < tend)
fend = tend;
-
- DBGA2("pci_unmap_sg: sg [%lx,%lx]\n", addr, size);
}
}
if (fend)
alpha_mv.mv_pci_tbi(hose, fstart, fend);
+
+ DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg));
}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index e80282155..31a818209 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -30,10 +30,6 @@
#include <linux/reboot.h>
#include <linux/console.h>
-#ifdef CONFIG_RTC
-#include <linux/mc146818rtc.h>
-#endif
-
#include <asm/reg.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -139,11 +135,6 @@ common_shutdown(int mode, char *restart_cmd)
#endif
}
-#ifdef CONFIG_RTC
- /* Reset rtc to defaults. */
- rtc_kill_pit();
-#endif
-
if (alpha_mv.kill_arch)
alpha_mv.kill_arch(mode);
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index fa92b3bc3..dd63de4d2 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -10,6 +10,7 @@ struct pt_regs;
struct task_struct;
struct pci_dev;
struct pci_controler;
+struct irqaction;
/* core_apecs.c */
extern struct pci_ops apecs_pci_ops;
@@ -46,6 +47,8 @@ extern void mcpcia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
/* core_polaris.c */
extern struct pci_ops polaris_pci_ops;
+extern int polaris_read_config_dword(struct pci_dev *, int, u32 *);
+extern int polaris_write_config_dword(struct pci_dev *, int, u32);
extern void polaris_init_arch(void);
extern void polaris_machine_check(u64, u64, struct pt_regs *);
#define polaris_pci_tbi ((void *)0)
@@ -84,9 +87,7 @@ extern int smp_boot_cpuid;
/* time.c */
extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs);
-extern void rtc_init_pit(void);
-extern void rtc_kill_pit(void);
-extern void common_init_pit(void);
+extern void common_init_rtc(struct irqaction *);
extern unsigned long est_cycle_freq;
/* smc37c93x.c */
@@ -101,7 +102,7 @@ extern void es1888_init(void);
/* ns87312.c */
extern void ns87312_enable_ide(long ide_base);
-/* fpregs.c */
+/* ../lib/fpreg.c */
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
extern unsigned long alpha_read_fp_reg (unsigned long reg);
@@ -134,7 +135,7 @@ extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *);
/* ../mm/init.c */
void srm_paging_stop(void);
-/* irq.h */
+/* irq.c */
#ifdef __SMP__
#define mcheck_expected(cpu) (cpu_data[cpu].mcheck_expected)
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index c92168195..112976bcb 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -30,9 +30,6 @@
#include <linux/ioport.h>
#include <linux/bootmem.h>
-#ifdef CONFIG_RTC
-#include <linux/timex.h>
-#endif
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h>
#endif
@@ -453,16 +450,6 @@ setup_arch(char **cmdline_p)
/* Reserve standard resources. */
reserve_std_resources();
- /* Initialize the timers. */
- /* ??? There is some circumstantial evidence that this needs
- to be done now rather than later in time_init, which would
- be more natural. Someone please explain or refute. */
-#if defined(CONFIG_RTC)
- rtc_init_pit();
-#else
- alpha_mv.init_pit();
-#endif
-
/*
* Give us a default console. TGA users will see nothing until
* chr_dev_init is called, rather late in the boot sequence.
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 30ed75ead..e3ae30973 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -33,6 +33,7 @@
#include <asm/unistd.h>
#include "proto.h"
+#include "irq_impl.h"
#define DEBUG_SMP 0
@@ -62,6 +63,7 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
static unsigned long smp_secondary_alive;
unsigned long cpu_present_mask; /* Which cpus ids came online. */
+static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */
static int max_cpus = -1; /* Command-line limitation. */
int smp_boot_cpuid; /* Which processor we booted from. */
@@ -506,7 +508,7 @@ setup_smp(void)
if ((cpu->flags & 0x1cc) == 0x1cc) {
smp_num_probed++;
/* Assume here that "whami" == index */
- cpu_present_mask |= (1L << i);
+ __cpu_present_mask |= (1L << i);
cpu->pal_revision = boot_cpu_palrev;
}
@@ -517,11 +519,12 @@ setup_smp(void)
}
} else {
smp_num_probed = 1;
- cpu_present_mask = (1L << smp_boot_cpuid);
+ __cpu_present_mask = (1L << smp_boot_cpuid);
}
+ cpu_present_mask = 1L << smp_boot_cpuid;
printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
- smp_num_probed, cpu_present_mask);
+ smp_num_probed, __cpu_present_mask);
}
/*
@@ -565,12 +568,13 @@ smp_boot_cpus(void)
if (i == smp_boot_cpuid)
continue;
- if (((cpu_present_mask >> i) & 1) == 0)
+ if (((__cpu_present_mask >> i) & 1) == 0)
continue;
if (smp_boot_one_cpu(i, cpu_count))
continue;
+ cpu_present_mask |= 1L << i;
cpu_count++;
}
@@ -623,7 +627,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs)
/* We need to make like a normal interrupt -- otherwise
timer interrupts ignore the global interrupt lock,
which would be a Bad Thing. */
- irq_enter(cpu, TIMER_IRQ);
+ irq_enter(cpu, RTC_IRQ);
update_one_process(current, 1, user, !user, cpu);
if (current->pid) {
@@ -647,7 +651,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs)
}
data->prof_counter = data->prof_multiplier;
- irq_exit(cpu, TIMER_IRQ);
+ irq_exit(cpu, RTC_IRQ);
}
}
@@ -868,6 +872,22 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
}
static void
+ipi_imb(void *ignored)
+{
+ imb();
+}
+
+void
+smp_imb(void)
+{
+ /* Must wait other processors to flush their icache before continue. */
+ if (smp_call_function(ipi_imb, NULL, 1, 1))
+ printk(KERN_CRIT "smp_imb: timed out\n");
+
+ imb();
+}
+
+static void
ipi_flush_tlb_all(void *ignored)
{
tbia();
diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
index 2a27bac5b..5498c72ec 100644
--- a/arch/alpha/kernel/sys_alcor.c
+++ b/arch/alpha/kernel/sys_alcor.c
@@ -27,49 +27,70 @@
#include <asm/core_cia.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-alcor_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for ENABLED irqs. */
+static unsigned long cached_irq_mask;
+
+static inline void
+alcor_update_irq_hw(unsigned long mask)
{
- if (irq >= 16) {
- /* On Alcor, at least, lines 20..30 are not connected and can
- generate spurrious interrupts if we turn them on while IRQ
- probing. So explicitly mask them out. */
- mask |= 0x7ff000000000UL;
-
- /* Note inverted sense of mask bits: */
- *(vuip)GRU_INT_MASK = ~(mask >> 16);
- mb();
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
+ *(vuip)GRU_INT_MASK = mask;
+ mb();
+}
+
+static inline void
+alcor_enable_irq(unsigned int irq)
+{
+ alcor_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+}
+
+static inline void
+alcor_disable_irq(unsigned int irq)
+{
+ alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
}
static void
-alcor_ack_irq(unsigned long irq)
+alcor_mask_and_ack_irq(unsigned int irq)
{
- if (irq < 16) {
- /* Ack the interrupt making it the lowest priority */
- /* First the slave .. */
- if (irq > 7) {
- outb(0xE0 | (irq - 8), 0xa0);
- irq = 2;
- }
- /* .. then the master */
- outb(0xE0 | irq, 0x20);
+ alcor_disable_irq(irq);
- /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
- *(vuip)GRU_INT_CLEAR = 0x80000000; mb();
- *(vuip)GRU_INT_CLEAR = 0x00000000; mb();
- }
+ /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
+ *(vuip)GRU_INT_CLEAR = 1 << (irq - 16); mb();
+ *(vuip)GRU_INT_CLEAR = 0; mb();
}
+static unsigned int
+alcor_startup_irq(unsigned int irq)
+{
+ alcor_enable_irq(irq);
+ return 0;
+}
+
+static void
+alcor_isa_mask_and_ack_irq(unsigned int irq)
+{
+ i8259a_mask_and_ack_irq(irq);
+
+ /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
+ *(vuip)GRU_INT_CLEAR = 0x80000000; mb();
+ *(vuip)GRU_INT_CLEAR = 0; mb();
+}
+
+static struct hw_interrupt_type alcor_irq_type = {
+ typename: "ALCOR",
+ startup: alcor_startup_irq,
+ shutdown: alcor_disable_irq,
+ enable: alcor_enable_irq,
+ disable: alcor_disable_irq,
+ ack: alcor_mask_and_ack_irq,
+ end: alcor_enable_irq,
+};
+
static void
alcor_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
@@ -89,26 +110,40 @@ alcor_device_interrupt(unsigned long vector, struct pt_regs *regs)
if (i == 31) {
isa_device_interrupt(vector, regs);
} else {
- handle_irq(16 + i, 16 + i, regs);
+ handle_irq(16 + i, regs);
}
}
}
-static void
+static void __init
alcor_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ long i;
if (alpha_using_srm)
alpha_mv.device_interrupt = srm_device_interrupt;
- *(vuip)GRU_INT_MASK = ~(alpha_irq_mask >> 16); mb(); /* invert */
- *(vuip)GRU_INT_EDGE = 0U; mb(); /* all are level */
+ *(vuip)GRU_INT_MASK = 0; mb(); /* all disabled */
+ *(vuip)GRU_INT_EDGE = 0; mb(); /* all are level */
*(vuip)GRU_INT_HILO = 0x80000000U; mb(); /* ISA only HI */
- *(vuip)GRU_INT_CLEAR = 0UL; mb(); /* all clear */
+ *(vuip)GRU_INT_CLEAR = 0; mb(); /* all clear */
+
+ for (i = 16; i < 48; ++i) {
+ /* On Alcor, at least, lines 20..30 are not connected
+ and can generate spurrious interrupts if we turn them
+ on while IRQ probing. */
+ if (i >= 16+20 && i <= 16+30)
+ continue;
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &alcor_irq_type;
+ }
+ i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
+
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
- enable_irq(16 + 31); /* enable (E)ISA PIC cascade */
- enable_irq(2); /* enable cascade */
+ setup_irq(16+31, &isa_cascade_irqaction);
}
@@ -203,14 +238,11 @@ struct alpha_machine_vector alcor_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 48,
- irq_probe_mask: ALCOR_PROBE_MASK,
- update_irq_hw: alcor_update_irq_hw,
- ack_irq: alcor_ack_irq,
device_interrupt: alcor_device_interrupt,
init_arch: cia_init_arch,
init_irq: alcor_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: alcor_kill_arch,
pci_map_irq: alcor_map_irq,
@@ -236,14 +268,11 @@ struct alpha_machine_vector xlt_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 48,
- irq_probe_mask: ALCOR_PROBE_MASK,
- update_irq_hw: alcor_update_irq_hw,
- ack_irq: alcor_ack_irq,
device_interrupt: alcor_device_interrupt,
init_arch: cia_init_arch,
init_irq: alcor_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: alcor_kill_arch,
pci_map_irq: alcor_map_irq,
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index bc4d2c2ba..1432496d8 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -31,42 +31,50 @@
#include <asm/core_pyxis.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-cabriolet_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned long cached_irq_mask = ~0UL;
+
+static inline void
+cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
{
- if (irq >= 16)
- outl(alpha_irq_mask >> 16, 0x804);
- else if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
+ int ofs = (irq - 16) / 8;
+ outb(mask >> (16 + ofs*3), 0x804 + ofs);
}
-
-/* Under SRM console, we must use the CSERVE PALcode routine to manage
- the interrupt mask for us. Otherwise, the kernel/HW get out of
- sync with what the PALcode thinks it needs to deliver/ignore. */
+static inline void
+cabriolet_enable_irq(unsigned int irq)
+{
+ cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
+}
static void
-cabriolet_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmaskp)
+cabriolet_disable_irq(unsigned int irq)
{
- if (irq >= 16) {
- if (unmaskp)
- cserve_ena(irq - 16);
- else
- cserve_dis(irq - 16);
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
+ cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
+}
+
+static unsigned int
+cabriolet_startup_irq(unsigned int irq)
+{
+ cabriolet_enable_irq(irq);
+ return 0; /* never anything pending */
}
+static struct hw_interrupt_type cabriolet_irq_type = {
+ typename: "CABRIOLET",
+ startup: cabriolet_startup_irq,
+ shutdown: cabriolet_disable_irq,
+ enable: cabriolet_enable_irq,
+ disable: cabriolet_disable_irq,
+ ack: cabriolet_disable_irq,
+ end: cabriolet_enable_irq,
+};
+
static void
cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
{
@@ -86,26 +94,36 @@ cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
if (i == 4) {
isa_device_interrupt(v, r);
} else {
- handle_irq(16 + i, 16 + i, r);
+ handle_irq(16 + i, r);
}
}
}
-static void
+static void __init
cabriolet_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ init_i8259a_irqs();
+ init_rtc_irq();
if (alpha_using_srm) {
- alpha_mv.update_irq_hw = cabriolet_srm_update_irq_hw;
alpha_mv.device_interrupt = srm_device_interrupt;
+ init_srm_irqs(35, 0);
}
else {
- outl(alpha_irq_mask >> 16, 0x804);
+ long i;
+
+ outb(0xff, 0x804);
+ outb(0xff, 0x805);
+ outb(0xff, 0x806);
+
+ for (i = 16; i < 35; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &cabriolet_irq_type;
+ }
}
- enable_irq(16 + 4); /* enable SIO cascade */
- enable_irq(2); /* enable cascade */
+ common_init_isa_dma();
+ setup_irq(16+4, &isa_cascade_irqaction);
}
@@ -260,14 +278,11 @@ struct alpha_machine_vector cabriolet_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 35,
- irq_probe_mask: _PROBE_MASK(35),
- update_irq_hw: cabriolet_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: cabriolet_device_interrupt,
init_arch: apecs_init_arch,
init_irq: cabriolet_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: cabriolet_init_pci,
kill_arch: NULL,
pci_map_irq: cabriolet_map_irq,
@@ -289,14 +304,11 @@ struct alpha_machine_vector eb164_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 35,
- irq_probe_mask: _PROBE_MASK(35),
- update_irq_hw: cabriolet_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: cabriolet_device_interrupt,
init_arch: cia_init_arch,
init_irq: cabriolet_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: cabriolet_init_pci,
pci_map_irq: cabriolet_map_irq,
pci_swizzle: common_swizzle,
@@ -317,14 +329,11 @@ struct alpha_machine_vector eb66p_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 35,
- irq_probe_mask: _PROBE_MASK(35),
- update_irq_hw: cabriolet_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: cabriolet_device_interrupt,
init_arch: lca_init_arch,
init_irq: cabriolet_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: cabriolet_init_pci,
pci_map_irq: eb66p_map_irq,
pci_swizzle: common_swizzle,
@@ -345,14 +354,11 @@ struct alpha_machine_vector lx164_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 35,
- irq_probe_mask: _PROBE_MASK(35),
- update_irq_hw: cabriolet_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: cabriolet_device_interrupt,
init_arch: pyxis_init_arch,
init_irq: cabriolet_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: alphapc164_init_pci,
pci_map_irq: alphapc164_map_irq,
pci_swizzle: common_swizzle,
@@ -373,14 +379,11 @@ struct alpha_machine_vector pc164_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 35,
- irq_probe_mask: _PROBE_MASK(35),
- update_irq_hw: cabriolet_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: cabriolet_device_interrupt,
init_arch: cia_init_arch,
init_irq: cabriolet_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: alphapc164_init_pci,
pci_map_irq: alphapc164_map_irq,
pci_swizzle: common_swizzle,
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index f0ef47183..fbebdd5a5 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -8,6 +8,7 @@
* Code supporting the DP264 (EV6+TSUNAMI).
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mm.h>
@@ -27,72 +28,150 @@
#include <asm/hwrpb.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-/*
- * HACK ALERT! only the boot cpu is used for interrupts.
- */
+static unsigned long cached_irq_mask;
+
+
+#define TSUNAMI_SET_IRQ_MASK(cpu, value) \
+do { \
+ volatile unsigned long *csr; \
+ csr = &TSUNAMI_cchip->dim##cpu##.csr; \
+ *csr = (value); \
+ mb(); \
+ *csr; \
+} while(0)
+
+static inline void
+do_flush_irq_mask(unsigned long value)
+{
+ switch (TSUNAMI_bootcpu) {
+ case 0:
+ TSUNAMI_SET_IRQ_MASK(0, value);
+ break;
+ case 1:
+ TSUNAMI_SET_IRQ_MASK(1, value);
+ break;
+ case 2:
+ TSUNAMI_SET_IRQ_MASK(2, value);
+ break;
+ case 3:
+ TSUNAMI_SET_IRQ_MASK(3, value);
+ break;
+ }
+}
+
+#ifdef CONFIG_SMP
+static inline void
+do_flush_smp_irq_mask(unsigned long value)
+{
+ extern unsigned long cpu_present_mask;
+ unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu);
+
+ if (other_cpus & 1)
+ TSUNAMI_SET_IRQ_MASK(0, value);
+ if (other_cpus & 2)
+ TSUNAMI_SET_IRQ_MASK(1, value);
+ if (other_cpus & 4)
+ TSUNAMI_SET_IRQ_MASK(2, value);
+ if (other_cpus & 8)
+ TSUNAMI_SET_IRQ_MASK(3, value);
+}
+#endif
static void
-dp264_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+dp264_flush_irq_mask(unsigned long mask)
{
- volatile unsigned long *csr;
+ unsigned long value;
- if (TSUNAMI_bootcpu < 2) {
- if (!TSUNAMI_bootcpu)
- csr = &TSUNAMI_cchip->dim0.csr;
- else
- csr = &TSUNAMI_cchip->dim1.csr;
- } else {
- if (TSUNAMI_bootcpu == 2)
- csr = &TSUNAMI_cchip->dim2.csr;
- else
- csr = &TSUNAMI_cchip->dim3.csr;
- }
+#ifdef CONFIG_SMP
+ do_flush_smp_irq_mask(mask);
+#endif
- *csr = ~mask;
- mb();
- *csr;
+ value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */
+ do_flush_irq_mask(value);
+}
- if (irq < 16) {
- if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
- }
+static void
+clipper_flush_irq_mask(unsigned long mask)
+{
+ unsigned long value;
+
+ value = mask >> 16;
+#ifdef CONFIG_SMP
+ do_flush_smp_irq_mask(value);
+#endif
+
+ value = value | (1UL << 55); /* master ISA enable */
+ do_flush_irq_mask(value);
+}
+
+static inline void
+dp264_enable_irq(unsigned int irq)
+{
+ cached_irq_mask |= 1UL << irq;
+ dp264_flush_irq_mask(cached_irq_mask);
}
static void
-clipper_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+dp264_disable_irq(unsigned int irq)
{
- if (irq >= 16) {
- volatile unsigned long *csr;
-
- if (TSUNAMI_bootcpu < 2)
- if (!TSUNAMI_bootcpu)
- csr = &TSUNAMI_cchip->dim0.csr;
- else
- csr = &TSUNAMI_cchip->dim1.csr;
- else
- if (TSUNAMI_bootcpu == 2)
- csr = &TSUNAMI_cchip->dim2.csr;
- else
- csr = &TSUNAMI_cchip->dim3.csr;
-
- *csr = (~mask >> 16) | (1UL << 55); /* master ISA enable */
- mb();
- *csr;
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
+ cached_irq_mask &= ~(1UL << irq);
+ dp264_flush_irq_mask(cached_irq_mask);
+}
+
+static unsigned int
+dp264_startup_irq(unsigned int irq)
+{
+ dp264_enable_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static inline void
+clipper_enable_irq(unsigned int irq)
+{
+ cached_irq_mask |= 1UL << irq;
+ clipper_flush_irq_mask(cached_irq_mask);
}
static void
+clipper_disable_irq(unsigned int irq)
+{
+ cached_irq_mask &= ~(1UL << irq);
+ clipper_flush_irq_mask(cached_irq_mask);
+}
+
+static unsigned int
+clipper_startup_irq(unsigned int irq)
+{
+ clipper_enable_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type dp264_irq_type = {
+ typename: "DP264",
+ startup: dp264_startup_irq,
+ shutdown: dp264_disable_irq,
+ enable: dp264_enable_irq,
+ disable: dp264_disable_irq,
+ ack: dp264_disable_irq,
+ end: dp264_enable_irq,
+};
+
+static struct hw_interrupt_type clipper_irq_type = {
+ typename: "CLIPPER",
+ startup: clipper_startup_irq,
+ shutdown: clipper_disable_irq,
+ enable: clipper_enable_irq,
+ disable: clipper_disable_irq,
+ ack: clipper_disable_irq,
+ end: clipper_enable_irq,
+};
+
+static void
dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
#if 1
@@ -126,9 +205,9 @@ dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
static void
dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq, ack;
+ int irq;
- ack = irq = (vector - 0x800) >> 4;
+ irq = (vector - 0x800) >> 4;
/*
* The SRM console reports PCI interrupts with a vector calculated by:
@@ -142,17 +221,17 @@ dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
* so we don't count them.
*/
if (irq >= 32)
- ack = irq = irq - 16;
+ irq -= 16;
- handle_irq(irq, ack, regs);
+ handle_irq(irq, regs);
}
static void
clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq, ack;
+ int irq;
- ack = irq = (vector - 0x800) >> 4;
+ irq = (vector - 0x800) >> 4;
/*
* The SRM console reports PCI interrupts with a vector calculated by:
@@ -166,7 +245,19 @@ clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
*
* Eg IRQ 24 is DRIR bit 8, etc, etc
*/
- handle_irq(irq, ack, regs);
+ handle_irq(irq, regs);
+}
+
+static void __init
+init_tsunami_irqs(struct hw_interrupt_type * ops)
+{
+ long i;
+
+ /* Only irqs between 16 and 47 are tsunami irqs. */
+ for (i = 16; i < 48; ++i) {
+ irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
+ irq_desc[i].handler = ops;
+ }
}
static void __init
@@ -180,10 +271,11 @@ dp264_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = dp264_srm_device_interrupt;
- dp264_update_irq_hw(16, alpha_irq_mask, 0);
+ dp264_flush_irq_mask(0UL);
- enable_irq(55); /* Enable ISA interrupt controller. */
- enable_irq(2);
+ init_i8259a_irqs();
+ init_rtc_irq();
+ init_tsunami_irqs(&dp264_irq_type);
}
static void __init
@@ -197,10 +289,11 @@ clipper_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = clipper_srm_device_interrupt;
- clipper_update_irq_hw(16, alpha_irq_mask, 0);
+ clipper_flush_irq_mask(0UL);
- enable_irq(55); /* Enable ISA interrupt controller. */
- enable_irq(2);
+ init_i8259a_irqs();
+ init_rtc_irq();
+ init_tsunami_irqs(&clipper_irq_type);
}
@@ -431,14 +524,11 @@ struct alpha_machine_vector dp264_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 64,
- irq_probe_mask: TSUNAMI_PROBE_MASK,
- update_irq_hw: dp264_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: dp264_device_interrupt,
init_arch: tsunami_init_arch,
init_irq: dp264_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: dp264_init_pci,
kill_arch: tsunami_kill_arch,
pci_map_irq: dp264_map_irq,
@@ -458,14 +548,11 @@ struct alpha_machine_vector monet_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 64,
- irq_probe_mask: TSUNAMI_PROBE_MASK,
- update_irq_hw: dp264_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: dp264_device_interrupt,
init_arch: tsunami_init_arch,
init_irq: dp264_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: monet_init_pci,
kill_arch: tsunami_kill_arch,
pci_map_irq: monet_map_irq,
@@ -484,14 +571,11 @@ struct alpha_machine_vector webbrick_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 64,
- irq_probe_mask: TSUNAMI_PROBE_MASK,
- update_irq_hw: dp264_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: dp264_device_interrupt,
init_arch: tsunami_init_arch,
init_irq: dp264_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: tsunami_kill_arch,
pci_map_irq: webbrick_map_irq,
@@ -510,14 +594,11 @@ struct alpha_machine_vector clipper_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 64,
- irq_probe_mask: TSUNAMI_PROBE_MASK,
- update_irq_hw: clipper_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: dp264_device_interrupt,
init_arch: tsunami_init_arch,
init_irq: clipper_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: tsunami_kill_arch,
pci_map_irq: clipper_map_irq,
diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
index e8e224715..0820bd5a0 100644
--- a/arch/alpha/kernel/sys_eb64p.c
+++ b/arch/alpha/kernel/sys_eb64p.c
@@ -28,25 +28,49 @@
#include <asm/core_lca.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-eb64p_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned int cached_irq_mask = -1;
+
+static inline void
+eb64p_update_irq_hw(unsigned int irq, unsigned long mask)
{
- if (irq >= 16)
- if (irq >= 24)
- outb(mask >> 24, 0x27);
- else
- outb(mask >> 16, 0x26);
- else if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
+ outb(mask >> (irq >= 24 ? 24 : 16), (irq >= 24 ? 0x27 : 0x26));
}
+static inline void
+eb64p_enable_irq(unsigned int irq)
+{
+ eb64p_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+}
+
+static inline void
+eb64p_disable_irq(unsigned int irq)
+{
+ eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+}
+
+static unsigned int
+eb64p_startup_irq(unsigned int irq)
+{
+ eb64p_enable_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type eb64p_irq_type = {
+ typename: "EB64P",
+ startup: eb64p_startup_irq,
+ shutdown: eb64p_disable_irq,
+ enable: eb64p_enable_irq,
+ disable: eb64p_disable_irq,
+ ack: eb64p_disable_irq,
+ end: eb64p_enable_irq,
+};
+
static void
eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
@@ -55,6 +79,7 @@ eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
/* Read the interrupt summary registers */
pld = inb(0x26) | (inb(0x27) << 8);
+
/*
* Now, for every possible bit set, work through
* them and call the appropriate interrupt handler.
@@ -66,7 +91,7 @@ eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
if (i == 5) {
isa_device_interrupt(vector, regs);
} else {
- handle_irq(16 + i, 16 + i, regs);
+ handle_irq(16 + i, regs);
}
}
}
@@ -74,6 +99,8 @@ eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
static void __init
eb64p_init_irq(void)
{
+ long i;
+
#ifdef CONFIG_ALPHA_GENERIC
/*
* CABRIO SRM may not set variation correctly, so here we test
@@ -82,21 +109,25 @@ eb64p_init_irq(void)
*/
if (inw(0x806) != 0xffff) {
extern struct alpha_machine_vector cabriolet_mv;
-#if 1
- printk("eb64p_init_irq: resetting for CABRIO\n");
-#endif
alpha_mv = cabriolet_mv;
alpha_mv.init_irq();
return;
}
#endif /* GENERIC */
- STANDARD_INIT_IRQ_PROLOG;
+ outb(0xff, 0x26);
+ outb(0xff, 0x27);
+
+ init_i8259a_irqs();
+ init_rtc_irq();
+
+ for (i = 16; i < 32; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &eb64p_irq_type;
+ }
- outb(alpha_irq_mask >> 16, 0x26);
- outb(alpha_irq_mask >> 24, 0x27);
- enable_irq(16 + 5); /* enable SIO cascade */
- enable_irq(2); /* enable cascade */
+ common_init_isa_dma();
+ setup_irq(16+5, &isa_cascade_irqaction);
}
/*
@@ -112,7 +143,7 @@ eb64p_init_irq(void)
* 3 Interrupt Line B from slot 1
* 4 Interrupt Line C from slot 0
* 5 Interrupt line from the two ISA PICs
- * 6 Tulip (slot
+ * 6 Tulip
* 7 NCR SCSI
*
* Summary @ 0x27
@@ -174,14 +205,11 @@ struct alpha_machine_vector eb64p_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 32,
- irq_probe_mask: _PROBE_MASK(32),
- update_irq_hw: eb64p_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: eb64p_device_interrupt,
init_arch: apecs_init_arch,
init_irq: eb64p_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: NULL,
pci_map_irq: eb64p_map_irq,
@@ -203,14 +231,11 @@ struct alpha_machine_vector eb66_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 32,
- irq_probe_mask: _PROBE_MASK(32),
- update_irq_hw: eb64p_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: eb64p_device_interrupt,
init_arch: lca_init_arch,
init_irq: eb64p_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
pci_map_irq: eb64p_map_irq,
pci_swizzle: common_swizzle,
diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
index 433abddfb..c4d120799 100644
--- a/arch/alpha/kernel/sys_eiger.c
+++ b/arch/alpha/kernel/sys_eiger.c
@@ -29,7 +29,7 @@
#include <asm/hwrpb.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
@@ -38,29 +38,54 @@
* HACK ALERT! only the boot cpu is used for interrupts.
*/
-static void
-eiger_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p)
+/* Note that this interrupt code is identical to TAKARA. */
+
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned long cached_irq_mask[2] = { -1, -1 };
+
+static inline void
+eiger_update_irq_hw(unsigned long irq, unsigned long mask)
{
- unsigned int regaddr;
- unsigned long mask;
+ int regaddr;
- if (irq <= 15) {
- if (irq <= 7)
- outb(alpha_irq_mask, 0x21); /* ISA PIC1 */
- else
- outb(alpha_irq_mask >> 8, 0xA1); /* ISA PIC2 */
- } else {
- if (irq > 63)
- mask = _alpha_irq_masks[1] << 16;
- else
- mask = _alpha_irq_masks[0] >> ((irq - 16) & 0x30);
+ mask = (irq >= 64 ? mask << 16 : mask >> ((irq - 16) & 0x30));
+ regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+ outl(mask & 0xffff0000UL, regaddr);
+}
- regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+static inline void
+eiger_enable_irq(unsigned int irq)
+{
+ unsigned long mask;
+ mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
+ eiger_update_irq_hw(irq, mask);
+}
- outl(mask & 0xffff0000UL, regaddr);
- }
+static void
+eiger_disable_irq(unsigned int irq)
+{
+ unsigned long mask;
+ mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
+ eiger_update_irq_hw(irq, mask);
+}
+
+static unsigned int
+eiger_startup_irq(unsigned int irq)
+{
+ eiger_enable_irq(irq);
+ return 0; /* never anything pending */
}
+static struct hw_interrupt_type eiger_irq_type = {
+ typename: "EIGER",
+ startup: eiger_startup_irq,
+ shutdown: eiger_disable_irq,
+ enable: eiger_enable_irq,
+ disable: eiger_disable_irq,
+ ack: eiger_disable_irq,
+ end: eiger_enable_irq,
+};
+
static void
eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
@@ -89,25 +114,27 @@ eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
* despatch an interrupt if it's set.
*/
- if (intstatus & 8) handle_irq(16+3, 16+3, regs);
- if (intstatus & 4) handle_irq(16+2, 16+2, regs);
- if (intstatus & 2) handle_irq(16+1, 16+1, regs);
- if (intstatus & 1) handle_irq(16+0, 16+0, regs);
+ if (intstatus & 8) handle_irq(16+3, regs);
+ if (intstatus & 4) handle_irq(16+2, regs);
+ if (intstatus & 2) handle_irq(16+1, regs);
+ if (intstatus & 1) handle_irq(16+0, regs);
} else {
- isa_device_interrupt (vector, regs);
+ isa_device_interrupt(vector, regs);
}
}
static void
eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq = (vector - 0x800) >> 4;
- handle_irq(irq, irq, regs);
+ int irq = (vector - 0x800) >> 4;
+ handle_irq(irq, regs);
}
static void __init
eiger_init_irq(void)
{
+ long i;
+
outb(0, DMA1_RESET_REG);
outb(0, DMA2_RESET_REG);
outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
@@ -116,9 +143,16 @@ eiger_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = eiger_srm_device_interrupt;
- eiger_update_irq_hw(16, alpha_irq_mask, 0);
+ for (i = 16; i < 128; i += 16)
+ eiger_update_irq_hw(i, -1);
- enable_irq(2);
+ init_i8259a_irqs();
+ init_rtc_irq();
+
+ for (i = 16; i < 128; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &eiger_irq_type;
+ }
}
static int __init
@@ -199,14 +233,11 @@ struct alpha_machine_vector eiger_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 128,
- irq_probe_mask: TSUNAMI_PROBE_MASK,
- update_irq_hw: eiger_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: eiger_device_interrupt,
init_arch: tsunami_init_arch,
init_irq: eiger_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: tsunami_kill_arch,
pci_map_irq: eiger_map_irq,
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index c2abe26f2..98dea0902 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -28,19 +28,10 @@
#include <asm/pgtable.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "machvec_impl.h"
-static void
-jensen_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
-}
-
/*
* Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
* 0x9X0 for the local motherboard interrupts..
@@ -66,51 +57,71 @@ jensen_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
*/
static void
-handle_nmi(struct pt_regs * regs)
+jensen_local_ack(unsigned int irq)
{
- printk("Whee.. NMI received. Probable hardware error\n");
- printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
+ /* irq1 is supposed to be the keyboard, silly Jensen. */
+ if (irq == 7)
+ i8259a_mask_and_ack_irq(1);
}
+static struct hw_interrupt_type jensen_local_irq_type = {
+ typename: "LOCAL",
+ startup: i8259a_startup_irq,
+ shutdown: i8259a_disable_irq,
+ enable: i8259a_enable_irq,
+ disable: i8259a_disable_irq,
+ ack: jensen_local_ack,
+ end: i8259a_enable_irq,
+};
+
static void
jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq, ack;
-
- ack = irq = (vector - 0x800) >> 4;
+ int irq;
switch (vector) {
- case 0x660: handle_nmi(regs); return;
+ case 0x660:
+ printk("Whee.. NMI received. Probable hardware error\n");
+ printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
+ return;
/* local device interrupts: */
- case 0x900: irq = 4, ack = -1; break; /* com1 -> irq 4 */
- case 0x920: irq = 3, ack = -1; break; /* com2 -> irq 3 */
- case 0x980: irq = 1, ack = -1; break; /* kbd -> irq 1 */
- case 0x990: irq = 9, ack = -1; break; /* mouse -> irq 9 */
+ case 0x900: irq = 4; break; /* com1 -> irq 4 */
+ case 0x920: irq = 3; break; /* com2 -> irq 3 */
+ case 0x980: irq = 1; break; /* kbd -> irq 1 */
+ case 0x990: irq = 9; break; /* mouse -> irq 9 */
+
default:
if (vector > 0x900) {
printk("Unknown local interrupt %lx\n", vector);
+ return;
}
- /* irq1 is supposed to be the keyboard, silly Jensen
- (is this really needed??) */
+ irq = (vector - 0x800) >> 4;
if (irq == 1)
irq = 7;
break;
}
- handle_irq(irq, ack, regs);
+ handle_irq(irq, regs);
}
-static void
+static void __init
jensen_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ init_i8259a_irqs();
+ init_rtc_irq();
- enable_irq(2); /* enable cascade */
+ irq_desc[1].handler = &jensen_local_irq_type;
+ irq_desc[4].handler = &jensen_local_irq_type;
+ irq_desc[3].handler = &jensen_local_irq_type;
+ irq_desc[7].handler = &jensen_local_irq_type;
+ irq_desc[9].handler = &jensen_local_irq_type;
+
+ common_init_isa_dma();
}
-static void
+static void __init
jensen_init_arch(void)
{
__direct_map_base = 0;
@@ -140,14 +151,11 @@ struct alpha_machine_vector jensen_mv __initmv = {
rtc_port: 0x170,
nr_irqs: 16,
- irq_probe_mask: _PROBE_MASK(16),
- update_irq_hw: jensen_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: jensen_device_interrupt,
init_arch: jensen_init_arch,
init_irq: jensen_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: NULL,
kill_arch: NULL,
};
diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c
index b2da23528..06457a0e8 100644
--- a/arch/alpha/kernel/sys_miata.c
+++ b/arch/alpha/kernel/sys_miata.c
@@ -25,71 +25,17 @@
#include <asm/core_pyxis.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
static void
-miata_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- if (irq >= 16) {
- /* Make CERTAIN none of the bogus ints get enabled... */
- *(vulp)PYXIS_INT_MASK =
- ~((long)mask >> 16) & ~0x400000000000063bUL;
- mb();
- /* ... and read it back to make sure it got written. */
- *(vulp)PYXIS_INT_MASK;
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
-}
-
-static void
-miata_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
- unsigned long pld, tmp;
- unsigned int i;
-
- /* Read the interrupt summary register of PYXIS */
- pld = *(vulp)PYXIS_INT_REQ;
-
- /*
- * For now, AND off any bits we are not interested in:
- * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8)
- * then all the PCI slots/INTXs (12-31).
- */
- /* Maybe HALT should only be used for SRM console boots? */
- pld &= 0x00000000fffff9c4UL;
-
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 7) {
- isa_device_interrupt(vector, regs);
- } else if (i == 6) {
- continue;
- } else {
- /* if not timer int */
- handle_irq(16 + i, 16 + i, regs);
- }
- *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
- tmp = *(vulp)PYXIS_INT_REQ;
- }
-}
-
-static void
miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq, ack;
+ int irq;
- ack = irq = (vector - 0x800) >> 4;
+ irq = (vector - 0x800) >> 4;
/*
* I really hate to do this, but the MIATA SRM console ignores the
@@ -106,34 +52,36 @@ miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
* So, here's this grotty hack... :-(
*/
if (irq >= 16)
- ack = irq = irq + 8;
+ irq = irq + 8;
- handle_irq(irq, ack, regs);
+ handle_irq(irq, regs);
}
static void __init
miata_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
-
if (alpha_using_srm)
alpha_mv.device_interrupt = miata_srm_device_interrupt;
- /* Note invert on MASK bits. */
- *(vulp)PYXIS_INT_MASK =
- ~((long)alpha_irq_mask >> 16) & ~0x400000000000063bUL; mb();
#if 0
/* These break on MiataGL so we'll try not to do it at all. */
*(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */
*(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */
#endif
- /* Clear upper timer. */
- *(vulp)PYXIS_INT_REQ = 0x4000000000000180UL; mb();
- enable_irq(16 + 2); /* enable HALT switch - SRM only? */
- enable_irq(16 + 6); /* enable timer */
- enable_irq(16 + 7); /* enable ISA PIC cascade */
- enable_irq(2); /* enable cascade */
+ init_i8259a_irqs();
+ init_rtc_irq();
+
+ /* Not interested in the bogus interrupts (3,10), Fan Fault (0),
+ NMI (1), or EIDE (9).
+
+ We also disable the risers (4,5), since we don't know how to
+ route the interrupts behind the bridge. */
+ init_pyxis_irqs(0x63b0000);
+
+ common_init_isa_dma();
+ setup_irq(16+2, &halt_switch_irqaction); /* SRM only? */
+ setup_irq(16+6, &timer_cascade_irqaction);
}
@@ -300,14 +248,11 @@ struct alpha_machine_vector miata_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 48,
- irq_probe_mask: _PROBE_MASK(48),
- update_irq_hw: miata_update_irq_hw,
- ack_irq: common_ack_irq,
- device_interrupt: miata_device_interrupt,
+ device_interrupt: pyxis_device_interrupt,
init_arch: pyxis_init_arch,
init_irq: miata_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: miata_init_pci,
kill_arch: miata_kill_arch,
pci_map_irq: miata_map_irq,
diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
index ac55371a6..936fa4f17 100644
--- a/arch/alpha/kernel/sys_mikasa.c
+++ b/arch/alpha/kernel/sys_mikasa.c
@@ -28,21 +28,49 @@
#include <asm/core_cia.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-mikasa_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+
+/* Note mask bit is true for ENABLED irqs. */
+static int cached_irq_mask;
+
+static inline void
+mikasa_update_irq_hw(int mask)
+{
+ outw(mask, 0x536);
+}
+
+static inline void
+mikasa_enable_irq(unsigned int irq)
+{
+ mikasa_update_irq_hw(cached_irq_mask |= 1 << (irq - 16));
+}
+
+static inline void
+mikasa_disable_irq(unsigned int irq)
{
- if (irq >= 16)
- outw(~(mask >> 16), 0x536); /* note invert */
- else if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
+ mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16)));
}
+static unsigned int
+mikasa_startup_irq(unsigned int irq)
+{
+ mikasa_enable_irq(irq);
+ return 0;
+}
+
+static struct hw_interrupt_type mikasa_irq_type = {
+ typename: "MIKASA",
+ startup: mikasa_startup_irq,
+ shutdown: mikasa_disable_irq,
+ enable: mikasa_enable_irq,
+ disable: mikasa_disable_irq,
+ ack: mikasa_disable_irq,
+ end: mikasa_enable_irq,
+};
+
static void
mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
@@ -50,9 +78,9 @@ mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
unsigned int i;
/* Read the interrupt summary registers */
- pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
- (((unsigned long) inb(0xa0)) << 8) |
- ((unsigned long) inb(0x20));
+ pld = (((~inw(0x534) & 0x0000ffffUL) << 16)
+ | (((unsigned long) inb(0xa0)) << 8)
+ | inb(0x20));
/*
* Now for every possible bit set, work through them and call
@@ -64,7 +92,7 @@ mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
if (i < 16) {
isa_device_interrupt(vector, regs);
} else {
- handle_irq(i, i, regs);
+ handle_irq(i, regs);
}
}
}
@@ -72,13 +100,21 @@ mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
static void __init
mikasa_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ long i;
if (alpha_using_srm)
alpha_mv.device_interrupt = srm_device_interrupt;
- outw(~(alpha_irq_mask >> 16), 0x536); /* note invert */
- enable_irq(2); /* enable cascade */
+ mikasa_update_irq_hw(0);
+
+ for (i = 16; i < 32; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &mikasa_irq_type;
+ }
+
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
}
@@ -185,14 +221,11 @@ struct alpha_machine_vector mikasa_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 32,
- irq_probe_mask: _PROBE_MASK(32),
- update_irq_hw: mikasa_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: mikasa_device_interrupt,
init_arch: apecs_init_arch,
init_irq: mikasa_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: NULL,
pci_map_irq: mikasa_map_irq,
@@ -214,14 +247,11 @@ struct alpha_machine_vector mikasa_primo_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 32,
- irq_probe_mask: _PROBE_MASK(32),
- update_irq_hw: mikasa_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: mikasa_device_interrupt,
init_arch: cia_init_arch,
init_irq: mikasa_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
pci_map_irq: mikasa_map_irq,
pci_swizzle: common_swizzle,
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 423589924..621df72f8 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -45,34 +45,17 @@
#include <asm/hwrpb.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index)
-
-static void
-nautilus_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- /* The timer is connected to PIC interrupt line also on Nautilus.
- The timer interrupt handler enables the PIC line, so in order
- not to get multiple timer interrupt sources, we mask it out
- at all times. */
-
- mask |= 0x100;
- if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
-}
static void __init
nautilus_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
-
- enable_irq(2); /* enable cascade */
- disable_irq(8);
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
}
static int __init
@@ -534,14 +517,11 @@ struct alpha_machine_vector nautilus_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 16,
- irq_probe_mask: (_PROBE_MASK(16) & ~0x101UL),
- update_irq_hw: nautilus_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: isa_device_interrupt,
init_arch: irongate_init_arch,
init_irq: nautilus_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: nautilus_kill_arch,
pci_map_irq: nautilus_map_irq,
diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
index c1a793393..31eac0da4 100644
--- a/arch/alpha/kernel/sys_noritake.c
+++ b/arch/alpha/kernel/sys_noritake.c
@@ -29,25 +29,51 @@
#include <asm/core_cia.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
+/* Note mask bit is true for ENABLED irqs. */
+static int cached_irq_mask;
-static void
-noritake_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+static inline void
+noritake_update_irq_hw(int irq, int mask)
{
- if (irq <= 15)
- if (irq <= 7)
- outb(mask, 0x21); /* ISA PIC1 */
- else
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else if (irq <= 31)
- outw(~(mask >> 16), 0x54a);
- else
- outw(~(mask >> 32), 0x54c);
+ int port = 0x54a;
+ if (irq >= 16) mask >>= 16;
+ if (irq >= 16) port = 0x54c;
+ outw(mask, port);
+}
+
+static inline void
+noritake_enable_irq(unsigned int irq)
+{
+ noritake_update_irq_hw(irq, cached_irq_mask |= 1 << (irq - 16));
+}
+
+static inline void
+noritake_disable_irq(unsigned int irq)
+{
+ noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16)));
}
+static unsigned int
+noritake_startup_irq(unsigned int irq)
+{
+ noritake_enable_irq(irq);
+ return 0;
+}
+
+static struct hw_interrupt_type noritake_irq_type = {
+ typename: "NORITAKE",
+ startup: noritake_startup_irq,
+ shutdown: noritake_disable_irq,
+ enable: noritake_enable_irq,
+ disable: noritake_disable_irq,
+ ack: noritake_disable_irq,
+ end: noritake_enable_irq,
+};
+
static void
noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
@@ -55,10 +81,10 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
unsigned int i;
/* Read the interrupt summary registers of NORITAKE */
- pld = ((unsigned long) inw(0x54c) << 32) |
- ((unsigned long) inw(0x54a) << 16) |
- ((unsigned long) inb(0xa0) << 8) |
- ((unsigned long) inb(0x20));
+ pld = (((unsigned long) inw(0x54c) << 32)
+ | ((unsigned long) inw(0x54a) << 16)
+ | ((unsigned long) inb(0xa0) << 8)
+ | inb(0x20));
/*
* Now for every possible bit set, work through them and call
@@ -70,7 +96,7 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
if (i < 16) {
isa_device_interrupt(vector, regs);
} else {
- handle_irq(i, i, regs);
+ handle_irq(i, regs);
}
}
}
@@ -78,36 +104,44 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
static void
noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
- int irq, ack;
+ int irq;
- ack = irq = (vector - 0x800) >> 4;
+ irq = (vector - 0x800) >> 4;
/*
* I really hate to do this, too, but the NORITAKE SRM console also
- * reports PCI vectors *lower* than I expected from the bit numbers
- * in the documentation.
+ * reports PCI vectors *lower* than I expected from the bit numbers
+ * in the documentation.
* But I really don't want to change the fixup code for allocation
- * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which
- * look nice and clean now.
+ * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which
+ * look nice and clean now.
* So, here's this additional grotty hack... :-(
*/
if (irq >= 16)
- ack = irq = irq + 1;
+ irq = irq + 1;
- handle_irq(irq, ack, regs);
+ handle_irq(irq, regs);
}
static void __init
noritake_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ long i;
if (alpha_using_srm)
alpha_mv.device_interrupt = noritake_srm_device_interrupt;
- outw(~(alpha_irq_mask >> 16), 0x54a); /* note invert */
- outw(~(alpha_irq_mask >> 32), 0x54c); /* note invert */
- enable_irq(2); /* enable cascade */
+ outw(0, 0x54a);
+ outw(0, 0x54c);
+
+ for (i = 16; i < 48; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &noritake_irq_type;
+ }
+
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
}
@@ -245,14 +279,11 @@ struct alpha_machine_vector noritake_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 48,
- irq_probe_mask: _PROBE_MASK(48),
- update_irq_hw: noritake_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: noritake_device_interrupt,
init_arch: apecs_init_arch,
init_irq: noritake_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: NULL,
pci_map_irq: noritake_map_irq,
@@ -274,14 +305,11 @@ struct alpha_machine_vector noritake_primo_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 48,
- irq_probe_mask: _PROBE_MASK(48),
- update_irq_hw: noritake_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: noritake_device_interrupt,
init_arch: cia_init_arch,
init_irq: noritake_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
pci_map_irq: noritake_map_irq,
pci_swizzle: noritake_swizzle,
diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
index 0a0ce2267..f956626a4 100644
--- a/arch/alpha/kernel/sys_rawhide.c
+++ b/arch/alpha/kernel/sys_rawhide.c
@@ -25,53 +25,77 @@
#include <asm/core_mcpcia.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
+
+/*
+ * HACK ALERT! only the boot cpu is used for interrupts.
+ */
+
+
+/* Note mask bit is true for ENABLED irqs. */
+
static unsigned int hose_irq_masks[4] = {
0xff0000, 0xfe0000, 0xff0000, 0xff0000
};
+static unsigned int cached_irq_masks[4];
+static inline void
+rawhide_update_irq_hw(int hose, int mask)
+{
+ *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)) = mask;
+ mb();
+ *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose));
+}
+
+static void
+rawhide_enable_irq(unsigned int irq)
+{
+ unsigned int mask, hose;
-/* Note that `mask' initially contains only the low 64 bits. */
+ irq -= 16;
+ hose = irq / 24;
+ irq -= hose * 24;
-static void
-rawhide_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+ mask = cached_irq_masks[hose] |= 1 << irq;
+ mask |= hose_irq_masks[hose];
+ rawhide_update_irq_hw(hose, mask);
+}
+
+static void
+rawhide_disable_irq(unsigned int irq)
{
- unsigned int saddle, hose, new_irq;
-
- if (irq < 16) {
- if (irq < 8)
- outb(mask, 0x21); /* ISA PIC1 */
- else
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- return;
- }
+ unsigned int mask, hose;
- saddle = (irq > 63);
- mask = _alpha_irq_masks[saddle];
+ irq -= 16;
+ hose = irq / 24;
+ irq -= hose * 24;
- if (saddle == 0) {
- /* Saddle 0 includes EISA interrupts. */
- mask >>= 16;
- new_irq = irq - 16;
- } else {
- new_irq = irq - 64;
- }
+ mask = cached_irq_masks[hose] &= ~(1 << irq);
+ mask |= hose_irq_masks[hose];
+ rawhide_update_irq_hw(hose, mask);
+}
- hose = saddle << 1;
- if (new_irq >= 24) {
- mask >>= 24;
- hose += 1;
- }
- *(vuip)MCPCIA_INT_MASK0(hose) =
- (~mask & 0x00ffffff) | hose_irq_masks[hose];
- mb();
- *(vuip)MCPCIA_INT_MASK0(hose);
+static unsigned int
+rawhide_startup_irq(unsigned int irq)
+{
+ rawhide_enable_irq(irq);
+ return 0;
}
+static struct hw_interrupt_type rawhide_irq_type = {
+ typename: "RAWHIDE",
+ startup: rawhide_startup_irq,
+ shutdown: rawhide_disable_irq,
+ enable: rawhide_enable_irq,
+ disable: rawhide_disable_irq,
+ ack: rawhide_disable_irq,
+ end: rawhide_enable_irq,
+};
+
static void
rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
@@ -97,28 +121,30 @@ rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
/* Adjust by which hose it is from. */
irq -= ((irq + 16) >> 2) & 0x38;
- handle_irq(irq, irq, regs);
+ handle_irq(irq, regs);
}
static void __init
rawhide_init_irq(void)
{
struct pci_controler *hose;
+ long i;
mcpcia_init_hoses();
- STANDARD_INIT_IRQ_PROLOG;
-
- /* HACK ALERT! Routing is only to CPU #0. */
for (hose = hose_head; hose; hose = hose->next) {
int h = hose->index;
+ rawhide_update_irq_hw(h, hose_irq_masks[h]);
+ }
- *(vuip)MCPCIA_INT_MASK0(h) = hose_irq_masks[h];
- mb();
- *(vuip)MCPCIA_INT_MASK0(h);
+ for (i = 16; i < 128; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &rawhide_irq_type;
}
- enable_irq(2);
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
}
/*
@@ -191,14 +217,11 @@ struct alpha_machine_vector rawhide_mv __initmv = {
min_mem_address: MCPCIA_DEFAULT_MEM_BASE,
nr_irqs: 128,
- irq_probe_mask: _PROBE_MASK(128),
- update_irq_hw: rawhide_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: rawhide_srm_device_interrupt,
init_arch: mcpcia_init_arch,
init_irq: rawhide_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: NULL,
pci_map_irq: rawhide_map_irq,
diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c
index c03a91296..ae89e81b2 100644
--- a/arch/alpha/kernel/sys_ruffian.c
+++ b/arch/alpha/kernel/sys_ruffian.c
@@ -26,117 +26,17 @@
#include <asm/core_pyxis.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-ruffian_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- if (irq >= 16) {
- /* Note inverted sense of mask bits: */
- /* Make CERTAIN none of the bogus ints get enabled... */
- *(vulp)PYXIS_INT_MASK =
- ~((long)mask >> 16) & 0x00000000ffffffbfUL;
- mb();
- /* ... and read it back to make sure it got written. */
- *(vulp)PYXIS_INT_MASK;
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
-}
-
-static void
-ruffian_ack_irq(unsigned long irq)
-{
- if (irq < 16) {
- /* Ack PYXIS ISA interrupt. */
- *(vulp)PYXIS_INT_REQ = 1L << 7; mb();
- /* ... and read it back to make sure it got written. */
- *(vulp)PYXIS_INT_REQ;
- if (irq > 7) {
- outb(0x20, 0xa0);
- }
- outb(0x20, 0x20);
- } else {
- /* Ack PYXIS PCI interrupt. */
- *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); mb();
- /* ... and read it back to make sure it got written. */
- *(vulp)PYXIS_INT_REQ;
- }
-}
-
-static void
-ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
- unsigned long pld;
- unsigned int i;
-
- /* Read the interrupt summary register of PYXIS */
- pld = *(vulp)PYXIS_INT_REQ;
-
- /* For now, AND off any bits we are not interested in:
- * HALT (2), timer (6), ISA Bridge (7), 21142 (8)
- * then all the PCI slots/INTXs (12-31)
- * flash(5) :DWH:
- */
- pld &= 0x00000000ffffff9fUL; /* was ffff7f */
-
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 7) { /* if ISA int */
- /* Ruffian does not have the RTC connected to
- the CPU timer interrupt. Instead, it uses the
- PIT connected to IRQ 0. So we must detect that
- and route that specifically to where we expected
- to find the timer interrupt come in. */
-
- /* Copy this code from isa_device_interrupt because
- we need to hook into int 0 for the timer. I
- refuse to soil device_interrupt with ifdefs. */
-
- /* Generate a PCI interrupt acknowledge cycle.
- The PIC will respond with the interrupt
- vector of the highest priority interrupt
- that is pending. The PALcode sets up the
- interrupts vectors such that irq level L
- generates vector L. */
-
- unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff;
- if (j == 7 && !(inb(0x20) & 0x80)) {
- /* It's only a passive release... */
- } else if (j == 0) {
- handle_irq(TIMER_IRQ, -1, regs);
- ruffian_ack_irq(0);
- } else {
- handle_irq(j, j, regs);
- }
- } else { /* if not an ISA int */
- handle_irq(16 + i, 16 + i, regs);
- }
-
- *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
- *(vulp)PYXIS_INT_REQ; /* read to force the write */
- }
-}
static void __init
ruffian_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
-
/* Invert 6&7 for i82371 */
*(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb();
*(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */
- *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb();
- *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb();
outb(0x11,0xA0);
outb(0x08,0xA1);
@@ -150,17 +50,54 @@ ruffian_init_irq(void)
outb(0x01,0x21);
outb(0xFF,0x21);
- /* Send -INTA pulses to clear any pending interrupts ...*/
- *(vuip) PYXIS_IACK_SC;
-
/* Finish writing the 82C59A PIC Operation Control Words */
outb(0x20,0xA0);
outb(0x20,0x20);
- /* Turn on the interrupt controller, the timer interrupt */
- enable_irq(16 + 7); /* enable ISA PIC cascade */
- enable_irq(0); /* enable timer */
- enable_irq(2); /* enable 2nd PIC cascade */
+ init_i8259a_irqs();
+
+ /* Not interested in the bogus interrupts (0,3,4,6),
+ NMI (1), HALT (2), flash (5), or 21142 (8). */
+ init_pyxis_irqs(0x17f0000);
+
+ common_init_isa_dma();
+}
+
+static void __init
+ruffian_init_rtc(struct irqaction *action)
+{
+ /* Ruffian does not have the RTC connected to the CPU timer
+ interrupt. Instead, it uses the PIT connected to IRQ 0. */
+
+ /* Setup interval timer. */
+ outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb(LATCH & 0xff, 0x40); /* LSB */
+ outb(LATCH >> 8, 0x40); /* MSB */
+
+ outb(0xb6, 0x43); /* pit counter 2: speaker */
+ outb(0x31, 0x42);
+ outb(0x13, 0x42);
+
+ setup_irq(0, action);
+}
+
+static void
+ruffian_kill_arch (int mode)
+{
+#if 0
+ /* This only causes re-entry to ARCSBIOS */
+ /* Perhaps this works for other PYXIS as well? */
+ *(vuip) PYXIS_RESET = 0x0000dead;
+ mb();
+#endif
+}
+
+static int __init
+ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /* We don't know anything about the PCI routing, so leave
+ the IRQ unchanged. */
+ return dev->irq;
}
@@ -203,34 +140,6 @@ ruffian_get_bank_size(unsigned long offset)
}
#endif /* BUILDING_FOR_MILO */
-static void
-ruffian_init_pit (void)
-{
- outb(0xb6, 0x43); /* pit counter 2: speaker */
- outb(0x31, 0x42);
- outb(0x13, 0x42);
-}
-
-static void
-ruffian_kill_arch (int mode)
-{
-#if 0
- /* This only causes re-entry to ARCSBIOS */
- /* Perhaps this works for other PYXIS as well? */
- *(vuip) PYXIS_RESET = 0x0000dead;
- mb();
-#endif
-}
-
-static int __init
-ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- /* We don't know anything about the PCI routing, so leave
- the IRQ unchanged. */
- return dev->irq;
-}
-
-
/*
* The System Vector
*/
@@ -247,14 +156,11 @@ struct alpha_machine_vector ruffian_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 48,
- irq_probe_mask: RUFFIAN_PROBE_MASK,
- update_irq_hw: ruffian_update_irq_hw,
- ack_irq: ruffian_ack_irq,
- device_interrupt: ruffian_device_interrupt,
+ device_interrupt: pyxis_device_interrupt,
init_arch: pyxis_init_arch,
init_irq: ruffian_init_irq,
- init_pit: ruffian_init_pit,
+ init_rtc: ruffian_init_rtc,
init_pci: common_init_pci,
kill_arch: ruffian_kill_arch,
pci_map_irq: ruffian_map_irq,
diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c
index 969d3561f..d5299d008 100644
--- a/arch/alpha/kernel/sys_rx164.c
+++ b/arch/alpha/kernel/sys_rx164.c
@@ -26,121 +26,103 @@
#include <asm/core_polaris.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-rx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for ENABLED irqs. */
+static unsigned long cached_irq_mask;
+
+/* Bus 0, Device 0. Nothing else matters, since we invoke the
+ POLARIS routines directly. */
+static struct pci_dev rx164_system;
+
+static inline void
+rx164_update_irq_hw(unsigned long mask)
{
- if (irq >= 16) {
- unsigned int temp;
- pcibios_write_config_dword(0, 0, 0x74, ~mask >> 16);
- pcibios_read_config_dword(0, 0, 0x74, &temp);
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
+ unsigned int temp;
+ polaris_write_config_dword(&rx164_system, 0x74, mask);
+ polaris_read_config_dword(&rx164_system, 0x74, &temp);
}
-#if 0
-static void
-rx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+static inline void
+rx164_enable_irq(unsigned int irq)
{
- if (irq >= 16) {
- if (unmask_p)
- cserve_ena(irq - 16);
- else
- cserve_dis(irq - 16);
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
+ rx164_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
}
-#endif
static void
-rx164_isa_device_interrupt(unsigned long vector, struct pt_regs * regs)
+rx164_disable_irq(unsigned int irq)
+{
+ rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+}
+
+static unsigned int
+rx164_startup_irq(unsigned int irq)
{
- unsigned long pic;
-
- /*
- * It seems to me that the probability of two or more *device*
- * interrupts occurring at almost exactly the same time is
- * pretty low. So why pay the price of checking for
- * additional interrupts here if the common case can be
- * handled so much easier?
- */
- /*
- * The first read of the PIC gives you *all* interrupting lines.
- * Therefore, read the mask register and and out those lines
- * not enabled. Note that some documentation has 21 and a1
- * write only. This is not true.
- */
- pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */
- pic &= ~alpha_irq_mask; /* apply mask */
- pic &= 0xFFFB; /* mask out cascade & hibits */
-
- while (pic) {
- int j = ffz(~pic);
- pic &= pic - 1;
- handle_irq(j, j, regs);
- }
+ rx164_enable_irq(irq);
+ return 0;
}
+static struct hw_interrupt_type rx164_irq_type = {
+ typename: "RX164",
+ startup: rx164_startup_irq,
+ shutdown: rx164_disable_irq,
+ enable: rx164_enable_irq,
+ disable: rx164_disable_irq,
+ ack: rx164_disable_irq,
+ end: rx164_enable_irq,
+};
+
static void
rx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
+ unsigned int temp;
unsigned long pld;
- int i;
-
- /* Read the interrupt summary register. On Polaris,
- * this is the DIRR register in PCI config space (offset 0x84)
- */
- pld = 0;
- pcibios_read_config_dword(0, 0, 0x84, (unsigned int *)&pld);
-
-#if 0
- printk("PLD 0x%lx\n", pld);
-#endif
-
- if (pld & 0xffffffff00000000UL)
- pld &= 0x00000000ffffffffUL;
-
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 20) {
- rx164_isa_device_interrupt(vector, regs);
- } else {
- handle_irq(16+i, 16+i, regs);
- }
- }
+ long i;
+
+ /* Read the interrupt summary register. On Polaris, this is
+ the DIRR register in PCI config space (offset 0x84). */
+ polaris_read_config_dword(&rx164_system, 0x84, &temp);
+ pld = temp;
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 20) {
+ isa_no_iack_sc_device_interrupt(vector, regs);
+ } else {
+ handle_irq(16+i, regs);
+ }
+ }
}
-static void
+static void __init
rx164_init_irq(void)
{
- unsigned int temp;
+ long i;
- STANDARD_INIT_IRQ_PROLOG;
+ rx164_update_irq_hw(0);
+ for (i = 16; i < 40; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &rx164_irq_type;
+ }
- pcibios_write_config_dword(0, 0, 0x74, (~alpha_irq_mask >> 16));
- pcibios_read_config_dword(0, 0, 0x74, &temp);
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
- enable_irq(16 + 20); /* enable ISA interrupts */
- enable_irq(2); /* enable cascade */
+ setup_irq(16+20, &isa_cascade_irqaction);
}
-/* The RX164 changed its interrupt routing between pass1 and pass2...
+/*
+ * The RX164 changed its interrupt routing between pass1 and pass2...
*
* PASS1:
*
@@ -176,29 +158,29 @@ static int __init
rx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
#if 0
- char irq_tab_pass1[6][5] = {
- /*INT INTA INTB INTC INTD */
- { 16+3, 16+3, 16+8, 16+13, 16+18}, /* IdSel 5, slot 2 */
- { 16+5, 16+5, 16+10, 16+15, 16+20}, /* IdSel 6, slot 0 */
- { 16+4, 16+4, 16+9, 16+14, 16+19}, /* IdSel 7, slot 1 */
- { -1, -1, -1, -1, -1}, /* IdSel 8, PCI/ISA bridge */
- { 16+2, 16+2, 16+7, 16+12, 16+17}, /* IdSel 9, slot 3 */
- { 16+1, 16+1, 16+6, 16+11, 16+16}, /* IdSel 10, slot 4 */
- };
+ static char irq_tab_pass1[6][5] __initlocaldata = {
+ /*INT INTA INTB INTC INTD */
+ { 16+3, 16+3, 16+8, 16+13, 16+18}, /* IdSel 5, slot 2 */
+ { 16+5, 16+5, 16+10, 16+15, 16+20}, /* IdSel 6, slot 0 */
+ { 16+4, 16+4, 16+9, 16+14, 16+19}, /* IdSel 7, slot 1 */
+ { -1, -1, -1, -1, -1}, /* IdSel 8, PCI/ISA bridge */
+ { 16+2, 16+2, 16+7, 16+12, 16+17}, /* IdSel 9, slot 3 */
+ { 16+1, 16+1, 16+6, 16+11, 16+16}, /* IdSel 10, slot 4 */
+ };
#else
- char irq_tab[6][5] = {
- /*INT INTA INTB INTC INTD */
- { 16+0, 16+0, 16+6, 16+11, 16+16}, /* IdSel 5, slot 0 */
- { 16+1, 16+1, 16+7, 16+12, 16+17}, /* IdSel 6, slot 1 */
- { -1, -1, -1, -1, -1}, /* IdSel 7, PCI/ISA bridge */
- { 16+2, 16+2, 16+8, 16+13, 16+18}, /* IdSel 8, slot 2 */
- { 16+3, 16+3, 16+9, 16+14, 16+19}, /* IdSel 9, slot 3 */
- { 16+4, 16+4, 16+10, 16+15, 16+5}, /* IdSel 10, PCI-PCI */
- };
+ static char irq_tab[6][5] __initlocaldata = {
+ /*INT INTA INTB INTC INTD */
+ { 16+0, 16+0, 16+6, 16+11, 16+16}, /* IdSel 5, slot 0 */
+ { 16+1, 16+1, 16+7, 16+12, 16+17}, /* IdSel 6, slot 1 */
+ { -1, -1, -1, -1, -1}, /* IdSel 7, PCI/ISA bridge */
+ { 16+2, 16+2, 16+8, 16+13, 16+18}, /* IdSel 8, slot 2 */
+ { 16+3, 16+3, 16+9, 16+14, 16+19}, /* IdSel 9, slot 3 */
+ { 16+4, 16+4, 16+10, 16+15, 16+5}, /* IdSel 10, PCI-PCI */
+ };
#endif
const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5;
- /* JRP - Need to figure out how to distinguish pass1 from pass2,
+ /* JRP - Need to figure out how to distinguish pass1 from pass2,
and use the correct table. */
return COMMON_TABLE_LOOKUP;
}
@@ -220,14 +202,11 @@ struct alpha_machine_vector rx164_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 40,
- irq_probe_mask: _PROBE_MASK(40),
- update_irq_hw: rx164_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: rx164_device_interrupt,
init_arch: polaris_init_arch,
init_irq: rx164_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: NULL,
pci_map_irq: rx164_map_irq,
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
index 53afe259b..e2a69b5c7 100644
--- a/arch/alpha/kernel/sys_sable.c
+++ b/arch/alpha/kernel/sys_sable.c
@@ -26,7 +26,7 @@
#include <asm/core_t2.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
@@ -38,15 +38,43 @@
* 0-7 (char at 536)
* 8-15 (char at 53a)
* 16-23 (char at 53c)
+ *
+ * Summary Registers (536/53a/53c):
+ *
+ * Bit Meaning Kernel IRQ
+ *------------------------------------------
+ * 0 PCI slot 0 34
+ * 1 NCR810 (builtin) 33
+ * 2 TULIP (builtin) 32
+ * 3 mouse 12
+ * 4 PCI slot 1 35
+ * 5 PCI slot 2 36
+ * 6 keyboard 1
+ * 7 floppy 6
+ * 8 COM2 3
+ * 9 parallel port 7
+ *10 EISA irq 3 -
+ *11 EISA irq 4 -
+ *12 EISA irq 5 5
+ *13 EISA irq 6 -
+ *14 EISA irq 7 -
+ *15 COM1 4
+ *16 EISA irq 9 9
+ *17 EISA irq 10 10
+ *18 EISA irq 11 11
+ *19 EISA irq 12 -
+ *20 EISA irq 13 -
+ *21 EISA irq 14 14
+ *22 NC 15
+ *23 IIC -
*/
-/* Note that the vector reported by the SRM PALcode corresponds to the
- interrupt mask bits, but we have to manage via more normal IRQs. */
-
static struct
{
char irq_to_mask[40];
char mask_to_irq[40];
+
+ /* Note mask bit is true for DISABLED irqs. */
unsigned long shadow_mask;
} sable_irq_swizzle = {
{
@@ -54,61 +82,103 @@ static struct
-1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */
-1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */
-1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */
- 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */
+ 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */
},
{
34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */
- 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
- 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
+ 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */
+ 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */
},
- 0
+ -1
};
+static inline void
+sable_update_irq_hw(unsigned long bit, unsigned long mask)
+{
+ int port = 0x536;
+
+ if (bit >= 16) {
+ port = 0x53d;
+ mask >>= 16;
+ } else if (bit >= 8) {
+ port = 0x53b;
+ mask >>= 8;
+ }
-static void
-sable_update_irq_hw(unsigned long irq, unsigned long unused_mask, int unmask_p)
+ outb(mask, port);
+}
+
+static inline void
+sable_ack_irq_hw(unsigned long bit)
+{
+ int port, val1, val2;
+
+ if (bit >= 16) {
+ port = 0x53c;
+ val1 = 0xE0 | (bit - 16);
+ val2 = 0xE0 | 4;
+ } else if (bit >= 8) {
+ port = 0x53a;
+ val1 = 0xE0 | (bit - 8);
+ val2 = 0xE0 | 2;
+ } else {
+ port = 0x536;
+ val1 = 0xE0 | (bit - 0);
+ val2 = 0xE0 | 1;
+ }
+
+ outb(val1, port); /* ack the slave */
+ outb(val2, 0x534); /* ack the master */
+}
+
+static inline void
+sable_enable_irq(unsigned int irq)
{
unsigned long bit, mask;
- /* The "irq" argument is really the irq, but we need it to
- be the mask bit number. Convert it now. */
-
- irq = sable_irq_swizzle.irq_to_mask[irq];
- bit = 1UL << irq;
- mask = sable_irq_swizzle.shadow_mask | bit;
- if (unmask_p)
- mask &= ~bit;
- sable_irq_swizzle.shadow_mask = mask;
-
- /* The "irq" argument is now really the mask bit number. */
- if (irq <= 7)
- outb(mask, 0x537);
- else if (irq <= 15)
- outb(mask >> 8, 0x53b);
- else
- outb(mask >> 16, 0x53d);
+ bit = sable_irq_swizzle.irq_to_mask[irq];
+ mask = sable_irq_swizzle.shadow_mask &= ~(1UL << bit);
+ sable_update_irq_hw(bit, mask);
}
static void
-sable_ack_irq(unsigned long irq)
+sable_disable_irq(unsigned int irq)
{
- /* Note that the "irq" here is really the mask bit number */
- switch (irq) {
- case 0 ... 7:
- outb(0xE0 | (irq - 0), 0x536);
- outb(0xE0 | 1, 0x534); /* slave 0 */
- break;
- case 8 ... 15:
- outb(0xE0 | (irq - 8), 0x53a);
- outb(0xE0 | 3, 0x534); /* slave 1 */
- break;
- case 16 ... 24:
- outb(0xE0 | (irq - 16), 0x53c);
- outb(0xE0 | 4, 0x534); /* slave 2 */
- break;
- }
+ unsigned long bit, mask;
+
+ bit = sable_irq_swizzle.irq_to_mask[irq];
+ mask = sable_irq_swizzle.shadow_mask |= 1UL << bit;
+ sable_update_irq_hw(bit, mask);
}
+static unsigned int
+sable_startup_irq(unsigned int irq)
+{
+ sable_enable_irq(irq);
+ return 0;
+}
+
+static void
+sable_mask_and_ack_irq(unsigned int irq)
+{
+ unsigned long bit, mask;
+
+ bit = sable_irq_swizzle.irq_to_mask[irq];
+ mask = sable_irq_swizzle.shadow_mask |= 1UL << bit;
+ sable_update_irq_hw(bit, mask);
+ sable_ack_irq_hw(bit);
+}
+
+static struct hw_interrupt_type sable_irq_type = {
+ typename: "SABLE",
+ startup: sable_startup_irq,
+ shutdown: sable_disable_irq,
+ enable: sable_enable_irq,
+ disable: sable_disable_irq,
+ ack: sable_mask_and_ack_irq,
+ end: sable_enable_irq,
+};
+
static void
sable_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
@@ -116,64 +186,36 @@ sable_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
to the interrupt mask bits, but we have to manage via more
normal IRQs. */
- int irq, ack;
-
- ack = irq = (vector - 0x800) >> 4;
-
- irq = sable_irq_swizzle.mask_to_irq[(ack)];
-#if 0
- if (irq == 5 || irq == 9 || irq == 10 || irq == 11 ||
- irq == 14 || irq == 15)
- printk("srm_device_interrupt: vector=0x%lx ack=0x%x"
- " irq=0x%x\n", vector, ack, irq);
-#endif
+ int bit, irq;
- handle_irq(irq, ack, regs);
+ bit = (vector - 0x800) >> 4;
+ irq = sable_irq_swizzle.mask_to_irq[bit];
+ handle_irq(irq, regs);
}
static void __init
sable_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ long i;
- outb(alpha_irq_mask , 0x537); /* slave 0 */
- outb(alpha_irq_mask >> 8, 0x53b); /* slave 1 */
- outb(alpha_irq_mask >> 16, 0x53d); /* slave 2 */
- outb(0x44, 0x535); /* enable cascades in master */
+ outb(-1, 0x537); /* slave 0 */
+ outb(-1, 0x53b); /* slave 1 */
+ outb(-1, 0x53d); /* slave 2 */
+ outb(0x44, 0x535); /* enable cascades in master */
+
+ for (i = 0; i < 40; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &sable_irq_type;
+ }
+
+ init_rtc_irq();
+ common_init_isa_dma();
}
/*
* PCI Fixup configuration for ALPHA SABLE (2100) - 2100A is different ??
*
- * Summary Registers (536/53a/53c):
- * Bit Meaning
- *-----------------
- * 0 PCI slot 0
- * 1 NCR810 (builtin)
- * 2 TULIP (builtin)
- * 3 mouse
- * 4 PCI slot 1
- * 5 PCI slot 2
- * 6 keyboard
- * 7 floppy
- * 8 COM2
- * 9 parallel port
- *10 EISA irq 3
- *11 EISA irq 4
- *12 EISA irq 5
- *13 EISA irq 6
- *14 EISA irq 7
- *15 COM1
- *16 EISA irq 9
- *17 EISA irq 10
- *18 EISA irq 11
- *19 EISA irq 12
- *20 EISA irq 13
- *21 EISA irq 14
- *22 NC
- *23 IIC
- *
* The device to slot mapping looks like:
*
* Slot Device
@@ -239,14 +281,11 @@ struct alpha_machine_vector sable_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 40,
- irq_probe_mask: _PROBE_MASK(40),
- update_irq_hw: sable_update_irq_hw,
- ack_irq: sable_ack_irq,
device_interrupt: sable_srm_device_interrupt,
init_arch: t2_init_arch,
init_irq: sable_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
kill_arch: NULL,
pci_map_irq: sable_map_irq,
@@ -274,14 +313,11 @@ struct alpha_machine_vector sable_gamma_mv __initmv = {
min_mem_address: DEFAULT_MEM_BASE,
nr_irqs: 40,
- irq_probe_mask: _PROBE_MASK(40),
- update_irq_hw: sable_update_irq_hw,
- ack_irq: sable_ack_irq,
device_interrupt: sable_srm_device_interrupt,
init_arch: t2_init_arch,
init_irq: sable_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: common_init_pci,
pci_map_irq: sable_map_irq,
pci_swizzle: common_swizzle,
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
index 2359755bf..ccdcf3bdb 100644
--- a/arch/alpha/kernel/sys_sio.c
+++ b/arch/alpha/kernel/sys_sio.c
@@ -30,28 +30,20 @@
#include <asm/core_lca.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-sio_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- if (irq >= 8)
- outb(mask >> 8, 0xA1);
- else
- outb(mask, 0x21);
-}
static void __init
sio_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
-
if (alpha_using_srm)
alpha_mv.device_interrupt = srm_device_interrupt;
-
- enable_irq(2); /* enable cascade */
+
+ init_i8259a_irqs();
+ init_rtc_irq();
+ common_init_isa_dma();
}
static inline void __init
@@ -270,14 +262,11 @@ struct alpha_machine_vector alphabook1_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 16,
- irq_probe_mask: _PROBE_MASK(16),
- update_irq_hw: sio_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: isa_device_interrupt,
init_arch: alphabook1_init_arch,
init_irq: sio_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: alphabook1_init_pci,
kill_arch: NULL,
pci_map_irq: noname_map_irq,
@@ -304,14 +293,11 @@ struct alpha_machine_vector avanti_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 16,
- irq_probe_mask: _PROBE_MASK(16),
- update_irq_hw: sio_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: isa_device_interrupt,
init_arch: apecs_init_arch,
init_irq: sio_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: noname_init_pci,
pci_map_irq: noname_map_irq,
pci_swizzle: common_swizzle,
@@ -336,14 +322,11 @@ struct alpha_machine_vector noname_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 16,
- irq_probe_mask: _PROBE_MASK(16),
- update_irq_hw: sio_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: srm_device_interrupt,
init_arch: lca_init_arch,
init_irq: sio_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: noname_init_pci,
pci_map_irq: noname_map_irq,
pci_swizzle: common_swizzle,
@@ -377,14 +360,11 @@ struct alpha_machine_vector p2k_mv __initmv = {
min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
nr_irqs: 16,
- irq_probe_mask: P2K_PROBE_MASK,
- update_irq_hw: sio_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: srm_device_interrupt,
init_arch: lca_init_arch,
init_irq: sio_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: noname_init_pci,
pci_map_irq: p2k_map_irq,
pci_swizzle: common_swizzle,
@@ -409,14 +389,11 @@ struct alpha_machine_vector xl_mv __initmv = {
min_mem_address: XL_DEFAULT_MEM_BASE,
nr_irqs: 16,
- irq_probe_mask: _PROBE_MASK(16),
- update_irq_hw: sio_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: isa_device_interrupt,
init_arch: lca_init_arch,
init_irq: sio_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: noname_init_pci,
pci_map_irq: noname_map_irq,
pci_swizzle: common_swizzle,
diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c
index 6ad08e442..806241a32 100644
--- a/arch/alpha/kernel/sys_sx164.c
+++ b/arch/alpha/kernel/sys_sx164.c
@@ -26,81 +26,12 @@
#include <asm/core_pyxis.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-sx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- if (irq >= 16) {
- /* Make CERTAIN none of the bogus ints get enabled */
- *(vulp)PYXIS_INT_MASK =
- ~((long)mask >> 16) & ~0x000000000000003bUL;
- mb();
- /* ... and read it back to make sure it got written. */
- *(vulp)PYXIS_INT_MASK;
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
-}
-
-static void
-sx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
-{
- if (irq >= 16) {
- if (unmask_p)
- cserve_ena(irq - 16);
- else
- cserve_dis(irq - 16);
- }
- else if (irq >= 8)
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- else
- outb(mask, 0x21); /* ISA PIC1 */
-}
-
-static void
-sx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
- unsigned long pld, tmp;
- unsigned int i;
-
- /* Read the interrupt summary register of PYXIS */
- pld = *(vulp)PYXIS_INT_REQ;
-
- /*
- * For now, AND off any bits we are not interested in:
- * HALT (2), timer (6), ISA Bridge (7)
- * then all the PCI slots/INTXs (8-23)
- */
- /* Maybe HALT should only be used for SRM console boots? */
- pld &= 0x0000000000ffffc0UL;
-
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 7) {
- isa_device_interrupt(vector, regs);
- } else if (i == 6) {
- continue;
- } else {
- /* if not timer int */
- handle_irq(16 + i, 16 + i, regs);
- }
- *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
- tmp = *(vulp)PYXIS_INT_REQ;
- }
-}
-
-static void
+static void __init
sx164_init_irq(void)
{
outb(0, DMA1_RESET_REG);
@@ -108,20 +39,20 @@ sx164_init_irq(void)
outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
outb(0, DMA2_MASK_REG);
- if (alpha_using_srm) {
- alpha_mv.update_irq_hw = sx164_srm_update_irq_hw;
+ if (alpha_using_srm)
alpha_mv.device_interrupt = srm_device_interrupt;
- }
- else {
- /* Note invert on MASK bits. */
- *(vulp)PYXIS_INT_MASK = ~((long)alpha_irq_mask >> 16);
- mb();
- *(vulp)PYXIS_INT_MASK;
- }
-
- enable_irq(16 + 6); /* enable timer */
- enable_irq(16 + 7); /* enable ISA PIC cascade */
- enable_irq(2); /* enable cascade */
+
+ init_i8259a_irqs();
+ init_rtc_irq();
+
+ /* Not interested in the bogus interrupts (0,3,4,5,40-47),
+ NMI (1), or HALT (2). */
+ if (alpha_using_srm)
+ init_srm_irqs(40, 0x3f0000);
+ else
+ init_pyxis_irqs(0xff00003f0000);
+
+ setup_irq(16+6, &timer_cascade_irqaction);
}
/*
@@ -160,7 +91,6 @@ sx164_init_irq(void)
* 7 64 bit PCI option slot 1
* 8 Cypress I/O
* 9 32 bit PCI option slot 3
- *
*/
static int __init
@@ -201,15 +131,12 @@ struct alpha_machine_vector sx164_mv __initmv = {
min_io_address: DEFAULT_IO_BASE,
min_mem_address: DEFAULT_MEM_BASE,
- nr_irqs: 40,
- irq_probe_mask: _PROBE_MASK(40),
- update_irq_hw: sx164_update_irq_hw,
- ack_irq: common_ack_irq,
- device_interrupt: sx164_device_interrupt,
+ nr_irqs: 48,
+ device_interrupt: pyxis_device_interrupt,
init_arch: pyxis_init_arch,
init_irq: sx164_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: sx164_init_pci,
kill_arch: NULL,
pci_map_irq: sx164_map_irq,
diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c
index a17cd4de6..360f135b6 100644
--- a/arch/alpha/kernel/sys_takara.c
+++ b/arch/alpha/kernel/sys_takara.c
@@ -25,32 +25,58 @@
#include <asm/core_cia.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
-static void
-takara_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+/* Note mask bit is true for DISABLED irqs. */
+static unsigned long cached_irq_mask[2] = { -1, -1 };
+
+static inline void
+takara_update_irq_hw(unsigned long irq, unsigned long mask)
{
- unsigned int regaddr;
+ int regaddr;
- if (irq <= 15) {
- if (irq <= 7)
- outb(mask, 0x21); /* ISA PIC1 */
- else
- outb(mask >> 8, 0xA1); /* ISA PIC2 */
- } else {
- if (irq > 63)
- mask = _alpha_irq_masks[1] << 16;
- else
- mask = mask >> ((irq - 16) & 0x30);
- regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
- outl(mask & 0xffff0000UL, regaddr);
- }
+ mask = (irq >= 64 ? mask << 16 : mask >> ((irq - 16) & 0x30));
+ regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c);
+ outl(mask & 0xffff0000UL, regaddr);
+}
+
+static inline void
+takara_enable_irq(unsigned int irq)
+{
+ unsigned long mask;
+ mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
+ takara_update_irq_hw(irq, mask);
}
static void
+takara_disable_irq(unsigned int irq)
+{
+ unsigned long mask;
+ mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
+ takara_update_irq_hw(irq, mask);
+}
+
+static unsigned int
+takara_startup_irq(unsigned int irq)
+{
+ takara_enable_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type takara_irq_type = {
+ typename: "TAKARA",
+ startup: takara_startup_irq,
+ shutdown: takara_disable_irq,
+ enable: takara_enable_irq,
+ disable: takara_disable_irq,
+ ack: takara_disable_irq,
+ end: takara_enable_irq,
+};
+
+static void
takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
unsigned intstatus;
@@ -78,10 +104,10 @@ takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
* despatch an interrupt if it's set.
*/
- if (intstatus & 8) handle_irq(16+3, 16+3, regs);
- if (intstatus & 4) handle_irq(16+2, 16+2, regs);
- if (intstatus & 2) handle_irq(16+1, 16+1, regs);
- if (intstatus & 1) handle_irq(16+0, 16+0, regs);
+ if (intstatus & 8) handle_irq(16+3, regs);
+ if (intstatus & 4) handle_irq(16+2, regs);
+ if (intstatus & 2) handle_irq(16+1, regs);
+ if (intstatus & 1) handle_irq(16+0, regs);
} else {
isa_device_interrupt (vector, regs);
}
@@ -91,13 +117,16 @@ static void
takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
int irq = (vector - 0x800) >> 4;
- handle_irq(irq, irq, regs);
+ handle_irq(irq, regs);
}
static void __init
takara_init_irq(void)
{
- STANDARD_INIT_IRQ_PROLOG;
+ long i;
+
+ init_i8259a_irqs();
+ init_rtc_irq();
if (alpha_using_srm) {
alpha_mv.device_interrupt = takara_srm_device_interrupt;
@@ -113,9 +142,18 @@ takara_init_irq(void)
outl(ctlreg, 0x500);
}
- enable_irq(2);
+ for (i = 16; i < 128; i += 16)
+ takara_update_irq_hw(i, -1);
+
+ for (i = 16; i < 128; ++i) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].handler = &takara_irq_type;
+ }
+
+ common_init_isa_dma();
}
+
/*
* The Takara has PCI devices 1, 2, and 3 configured to slots 20,
* 19, and 18 respectively, in the default configuration. They can
@@ -235,14 +273,11 @@ struct alpha_machine_vector takara_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 128,
- irq_probe_mask: _PROBE_MASK(48),
- update_irq_hw: takara_update_irq_hw,
- ack_irq: common_ack_irq,
device_interrupt: takara_device_interrupt,
init_arch: cia_init_arch,
init_irq: takara_init_irq,
- init_pit: common_init_pit,
+ init_rtc: common_init_rtc,
init_pci: takara_init_pci,
kill_arch: NULL,
pci_map_irq: takara_map_irq,
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 6e528e08f..8211045e8 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -31,6 +31,8 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -40,7 +42,7 @@
#include <linux/timex.h>
#include "proto.h"
-#include <asm/hw_irq.h>
+#include "irq_impl.h"
extern rwlock_t xtime_lock;
extern volatile unsigned long lost_ticks; /* kernel/sched.c */
@@ -88,13 +90,7 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
__u32 now;
long nticks;
-#ifdef __SMP__
- /* When SMP, do this for *all* CPUs, but only do the rest for
- the boot CPU. */
- smp_percpu_timer_interrupt(regs);
- if (smp_processor_id() != smp_boot_cpuid)
- return;
-#else
+#ifndef __SMP__
/* Not SMP, do kernel PC profiling here. */
if (!user_mode(regs))
alpha_do_profile(regs->pc);
@@ -167,55 +163,8 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon,
)*60 + sec; /* finally seconds */
}
-/*
- * Initialize Programmable Interval Timers with standard values. Some
- * drivers depend on them being initialized (e.g., joystick driver).
- */
-
-#ifdef CONFIG_RTC
void
-rtc_init_pit(void)
-{
- unsigned char control;
-
- /* Turn off RTC interrupts before /dev/rtc is initialized */
- control = CMOS_READ(RTC_CONTROL);
- control &= ~(RTC_PIE | RTC_AIE | RTC_UIE);
- CMOS_WRITE(control, RTC_CONTROL);
- (void) CMOS_READ(RTC_INTR_FLAGS);
-
- /* Setup interval timer. */
- outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb(LATCH & 0xff, 0x40); /* LSB */
- outb(LATCH >> 8, 0x40); /* MSB */
-
- outb(0xb6, 0x43); /* pit counter 2: speaker */
- outb(0x31, 0x42);
- outb(0x13, 0x42);
-}
-
-void
-rtc_kill_pit(void)
-{
- unsigned char control;
-
- cli();
-
- /* Reset periodic interrupt frequency. */
- CMOS_WRITE(0x26, RTC_FREQ_SELECT);
-
- /* Turn on periodic interrupts. */
- control = CMOS_READ(RTC_CONTROL);
- control |= RTC_PIE;
- CMOS_WRITE(control, RTC_CONTROL);
- CMOS_READ(RTC_INTR_FLAGS);
-
- sti();
-}
-#endif
-
-void
-common_init_pit (void)
+common_init_rtc(struct irqaction *action)
{
unsigned char x;
@@ -243,12 +192,19 @@ common_init_pit (void)
outb(0xb6, 0x43); /* pit counter 2: speaker */
outb(0x31, 0x42);
outb(0x13, 0x42);
+
+ setup_irq(RTC_IRQ, action);
}
void
time_init(void)
{
- void (*irq_handler)(int, void *, struct pt_regs *);
+ static struct irqaction timer_irqaction = {
+ handler: timer_interrupt,
+ flags: SA_INTERRUPT,
+ name: "timer",
+ };
+
unsigned int year, mon, day, hour, min, sec, cc1, cc2;
unsigned long cycle_freq, one_percent;
long diff;
@@ -336,10 +292,8 @@ time_init(void)
state.last_rtc_update = 0;
state.partial_tick = 0L;
- /* setup timer */
- irq_handler = timer_interrupt;
- if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
- panic("Could not allocate timer IRQ!");
+ /* Startup the timer source. */
+ alpha_mv.init_rtc(&timer_irqaction);
}
/*