diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-24 00:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-24 00:12:35 +0000 |
commit | 482368b1a8e45430672c58c9a42e7d2004367126 (patch) | |
tree | ce2a1a567d4d62dee7c2e71a46a99cf72cf1d606 /arch/alpha/kernel | |
parent | e4d0251c6f56ab2e191afb70f80f382793e23f74 (diff) |
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'arch/alpha/kernel')
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(®s); 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, ®s); +#ifdef CONFIG_SMP + cpu_data[smp_processor_id()].smp_local_irq_count++; + smp_percpu_timer_interrupt(®s); + if (smp_processor_id() == smp_boot_cpuid) +#endif + handle_irq(RTC_IRQ, ®s); return; case 2: alpha_mv.machine_check(vector, la_ptr, ®s); @@ -794,12 +1070,22 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr, perf_irq(vector, ®s); 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); } /* |