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 | |
parent | e4d0251c6f56ab2e191afb70f80f382793e23f74 (diff) |
Merge with 2.3.47. Guys, this is buggy as shit. You've been warned.
Diffstat (limited to 'arch')
181 files changed, 6958 insertions, 8409 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); } /* diff --git a/arch/alpha/lib/csum_ipv6_magic.S b/arch/alpha/lib/csum_ipv6_magic.S index 495375a1a..5a6e69c54 100644 --- a/arch/alpha/lib/csum_ipv6_magic.S +++ b/arch/alpha/lib/csum_ipv6_magic.S @@ -18,7 +18,7 @@ csum_ipv6_magic: ldq $0,0($16) # e0 : load src & dst addr words zapnot $20,15,$20 # .. e1 : zero extend incoming csum - extqh $18,7,$4 # e0 : byte swap len & proto while we wait + extqh $18,1,$4 # e0 : byte swap len & proto while we wait ldq $1,8($16) # .. e1 : extbl $18,1,$5 # e0 : diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 0caf4bf26..63d4631a4 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -188,6 +188,10 @@ EXPORT_SYMBOL(uaccess_kernel); EXPORT_SYMBOL(uaccess_user); #endif +EXPORT_SYMBOL(consistent_alloc); +EXPORT_SYMBOL(consistent_free); +EXPORT_SYMBOL(consistent_sync); + /* gcc lib functions */ EXPORT_SYMBOL_NOVERS(__gcc_bcmp); EXPORT_SYMBOL_NOVERS(__ashldi3); @@ -234,5 +238,8 @@ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); EXPORT_SYMBOL_NOVERS(__down_trylock_failed); EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); EXPORT_SYMBOL(get_wchan); diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 2be1a6012..5dc61c6d7 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -15,26 +15,28 @@ #define HARVARD_CACHE #endif + .macro get_softirq, rd +#ifdef __SMP__ +#error SMP not supported +#else + ldr \rd, __softirq_state +#endif + .endm + .globl ret_from_sys_call .align 5 fast_syscall_return: - str r0, [sp, #S_R0 + S_OFF] @ returned r0 + str r0, [sp, #S_R0 + S_OFF] @ returned r0 slow_syscall_return: add sp, sp, #S_OFF -ret_from_sys_call: -#ifdef HARVARD_CACHE - ldr r0, bh_data - ldr r4, bh_data+4 -#else - adr r0, bh_data - ldmia r0, {r0, r4} -#endif - ldr r0, [r0] - ldr r1, [r4] +ret_from_sys_call: @ external entry + get_softirq r0 + ldmia r0, {r0, r1} + mov r4, #1 @ flag this as being syscall return tst r0, r1 - blne SYMBOL_NAME(do_bottom_half) -ret_with_reschedule: + blne SYMBOL_NAME(do_softirq) +ret_with_reschedule: @ external entry (__irq_usr) get_current_task r5 ldr r0, [r5, #TSK_NEED_RESCHED] ldr r1, [r5, #TSK_SIGPENDING] @@ -43,30 +45,23 @@ ret_with_reschedule: teq r1, #0 @ check for signals bne ret_signal -ret_from_all: restore_user_regs +ret_from_all: restore_user_regs @ internal -ret_signal: mov r1, sp +ret_signal: mov r1, sp @ internal adrsvc al, lr, ret_from_all mov r2, r4 b SYMBOL_NAME(do_signal) -ret_reschedule: adrsvc al, lr, ret_with_reschedule +ret_reschedule: adrsvc al, lr, ret_with_reschedule @ internal b SYMBOL_NAME(schedule) .globl ret_from_exception -ret_from_exception: -#ifdef HARVARD_CACHE - ldr r0, bh_data - ldr r1, bh_data + 4 -#else - adr r0, bh_data +ret_from_exception: @ external entry + get_softirq r0 ldmia r0, {r0, r1} -#endif - ldr r0, [r0] - ldr r1, [r1] mov r4, #0 tst r0, r1 - blne SYMBOL_NAME(do_bottom_half) + blne SYMBOL_NAME(do_softirq) ldr r0, [sp, #S_PSR] tst r0, #3 @ returning to user mode? beq ret_with_reschedule @@ -147,8 +142,8 @@ vector_swi: save_user_regs .align 5 -bh_data: .word SYMBOL_NAME(bh_mask) - .word SYMBOL_NAME(bh_active) +__softirq_state: + .word SYMBOL_NAME(softirq_state) ENTRY(sys_call_table) #include "calls.S" diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index f6c310905..6e3c863d5 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -237,16 +237,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) irq_exit(cpu, irq); - /* - * This should be conditional: we should really get - * a return code from the irq handler to tell us - * whether the handler wants us to do software bottom - * half handling or not.. - */ - if (1) { - if (bh_active & bh_mask) - do_bottom_half(); - } + if (softirq_state[cpu].active & softirq_state[cpu].mask) + do_softirq(); } #if defined(CONFIG_ARCH_ACORN) diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c index 71bf85e09..a2ec71526 100644 --- a/arch/arm/kernel/semaphore.c +++ b/arch/arm/kernel/semaphore.c @@ -164,6 +164,126 @@ int __down_trylock(struct semaphore * sem) return 1; } +struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!sem->read_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!sem->write_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); + + return sem; +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + /* this takes care of granting the lock */ + __up_op_read(sem, __rwsem_wake); + + add_wait_queue(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + /* this takes care of granting the lock */ + __up_op_write(sem, __rwsem_wake); + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (atomic_read(&sem->count) >= 0) + break; /* we must attempt to aquire or bias the lock */ schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +/* Called when someone has done an up that transitioned from + * negative to non-negative, meaning that the lock has been + * granted to whomever owned the bias. + */ +struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) +{ + if (xchg(&sem->read_bias_granted, 1)) + BUG(); + wake_up(&sem->wait); + return sem; +} + +struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) +{ + if (xchg(&sem->write_bias_granted, 1)) + BUG(); + wake_up(&sem->write_bias_wait); + return sem; +} + /* * The semaphore operations have a special calling sequence that * allow us to do a simpler in-line version of them. These routines @@ -174,30 +294,65 @@ int __down_trylock(struct semaphore * sem) * registers (r0 to r3, ip and lr) except r0 in the cases where it * is used as a return value.. */ -asm(".align 5 +asm(" .section .text.lock, \"ax\" + .align 5 .globl __down_failed __down_failed: stmfd sp!, {r0 - r3, ip, lr} bl __down - ldmfd sp!, {r0 - r3, ip, pc}"); + ldmfd sp!, {r0 - r3, ip, pc} -asm(".align 5 + .align 5 .globl __down_interruptible_failed __down_interruptible_failed: stmfd sp!, {r1 - r3, ip, lr} bl __down_interruptible - ldmfd sp!, {r1 - r3, ip, pc}"); + ldmfd sp!, {r1 - r3, ip, pc} -asm(".align 5 + .align 5 .globl __down_trylock_failed __down_trylock_failed: stmfd sp!, {r1 - r3, ip, lr} bl __down_trylock - ldmfd sp!, {r1 - r3, ip, pc}"); + ldmfd sp!, {r1 - r3, ip, pc} -asm(".align 5 + .align 5 .globl __up_wakeup __up_wakeup: stmfd sp!, {r0 - r3, ip, lr} bl __up - ldmfd sp!, {r0 - r3, ip, pc}"); + ldmfd sp!, {r0 - r3, ip, pc} + + .align 5 + .globl __down_read_failed +__down_read_failed: + stmfd sp!, {r0 - r3, ip, lr} + bcc 1f + bl down_read_failed_biased + ldmfd sp!, {r0 - r3, ip, pc} +1: bl down_read_failed + /***/ + + .align 5 + .globl __down_write_failed +__down_write_failed: + stmfd sp!, {r0 - r3, ip, lr} + bcc 1f + bl down_write_failed_biased + ldmfd sp!, {r0 - r3, ip, pc} +1: bl down_write_failed + /***/ + + .align 5 + .globl __rwsem_wake +__rwsem_wake: + stmfd sp!, {r0 - r3, ip, lr} + beq 1f + bl rwsem_wake_readers + ldmfd sp!, {r0 - r3, ip, pc} +1: bl rwsem_wake_writer + ldmfd sp!, {r0 - r3, ip, pc} + + .previous + "); + diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index b9bffb7c9..1c02473bb 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -8,8 +8,8 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(PROCESSOR).o \ - small_page.o +O_OBJS := consistent.o extable.o fault-$(PROCESSOR).o init.o \ + mm-$(PROCESSOR).o small_page.o ifeq ($(CONFIG_CPU_26),y) O_OBJS += proc-arm2,3.o diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c new file mode 100644 index 000000000..8673d6c1d --- /dev/null +++ b/arch/arm/mm/consistent.c @@ -0,0 +1,88 @@ +/* + * Dynamic DMA mapping support. + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/errno.h> + +#include <asm/io.h> +#include <asm/pgalloc.h> + +/* + * This allocates one page of cache-coherent memory space and returns + * both the virtual and a "dma" address to that space. It is not clear + * whether this could be called from an interrupt context or not. For + * now, we expressly forbid it, especially as some of the stuff we do + * here is not interrupt context safe. + */ +void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) +{ + int order; + unsigned long page; + struct vm_struct *area; + void *ret; + + if (in_interrupt()) + BUG(); + + order = get_order(size); + + page = __get_free_pages(gfp, order); + if (!page) + goto no_page; + + memset((void *)page, 0, PAGE_SIZE << order); + clean_cache_area(page, PAGE_SIZE << order); + + *dma_handle = virt_to_bus((void *)page); + + area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */ + if (!area) + goto no_area; + + ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0); + if (ret) + return ret; + +no_area: + free_pages(page, order); +no_page: + BUG(); + return NULL; +} + +/* + * free a page as defined by the above mapping. We expressly forbid + * calling this from interrupt context. + */ +void consistent_free(void *vaddr) +{ + if (in_interrupt()) + BUG(); + + __iounmap(vaddr); +} + +/* + * make an area consistent. + */ +void consistent_sync(void *vaddr, size_t size, int rw) +{ + switch (rw) { + case 0: + BUG(); + case 1: /* invalidate only */ + dma_cache_inv(vaddr, size); + break; + case 2: /* writeback only */ + dma_cache_wback(vaddr, size); + break; + case 3: /* writeback and invalidate */ + dma_cache_wback_inv(vaddr, size); + break; + } +} diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index db3ac5a4d..c58e66647 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -163,7 +163,7 @@ void show_mem(void) void __init paging_init(void) { void *zero_page, *bad_page, *bad_table; - unsigned int zone_size[MAX_NR_ZONES]; + unsigned long zone_size[MAX_NR_ZONES]; int i; #ifdef CONFIG_CPU_32 diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S index 23508c197..c6c776acf 100644 --- a/arch/arm/mm/proc-arm6,7.S +++ b/arch/arm/mm/proc-arm6,7.S @@ -30,6 +30,8 @@ ENTRY(cpu_arm6_flush_cache_entry) ENTRY(cpu_arm7_flush_cache_entry) ENTRY(cpu_arm6_flush_icache_area) ENTRY(cpu_arm7_flush_icache_area) +ENTRY(cpu_arm6_flush_icache_page) +ENTRY(cpu_arm7_flush_icache_page) ENTRY(cpu_arm6_cache_wback_area) ENTRY(cpu_arm7_cache_wback_area) ENTRY(cpu_arm6_cache_purge_area) @@ -103,9 +105,9 @@ msg: .ascii "DA*%p=%p\n\0" .align ENTRY(cpu_arm6_data_abort) -Ldata_simple: ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L +Ldata_simple: and r2, r2, #2 @ check read/write bit mrc p15, 0, r0, c6, c0, 0 @ get FAR mrc p15, 0, r1, c5, c0, 0 @ get FSR @@ -465,6 +467,7 @@ ENTRY(arm6_processor_functions) .word cpu_arm6_cache_purge_area .word cpu_arm6_flush_tlb_page .word cpu_arm6_do_idle + .word cpu_arm6_flush_icache_page .size arm6_processor_functions, . - arm6_processor_functions /* @@ -493,6 +496,7 @@ ENTRY(arm7_processor_functions) .word cpu_arm7_cache_purge_area .word cpu_arm7_flush_tlb_page .word cpu_arm7_do_idle + .word cpu_arm7_flush_icache_page .size arm7_processor_functions, . - arm7_processor_functions .type cpu_arm6_info, #object diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index 5431f14a0..933408451 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -287,6 +287,12 @@ ENTRY(cpu_sa1100_flush_icache_area) mcr p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr + .align 5 +ENTRY(cpu_sa110_flush_icache_page) +ENTRY(cpu_sa1100_flush_icache_page) + mcr p15, 0, r0, c7, c5, 0 @ flush I cache + mov pc, lr + /* * Function: sa110_data_abort () * Params : r0 = address of aborted instruction @@ -504,6 +510,7 @@ ENTRY(sa110_processor_functions) .word cpu_sa110_cache_purge_area .word cpu_sa110_flush_tlb_page .word cpu_sa110_do_idle + .word cpu_sa110_flush_icache_page .size sa110_processor_functions, . - sa110_processor_functions .type cpu_sa110_info, #object @@ -535,6 +542,7 @@ ENTRY(sa1100_processor_functions) .word cpu_sa1100_cache_purge_area .word cpu_sa1100_flush_tlb_page .word cpu_sa1100_do_idle + .word cpu_sa1100_flush_icache_page .size sa1100_processor_functions, . - sa1100_processor_functions cpu_sa1100_info: diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c index b9ca935eb..9d4f1570d 100644 --- a/arch/arm/nwfpe/fpmodule.c +++ b/arch/arm/nwfpe/fpmodule.c @@ -128,23 +128,41 @@ cumulative exceptions flag byte are set and we return. void float_raise(signed char flags) { + register unsigned int fpsr, cumulativeTraps; + #ifdef CONFIG_DEBUG_USER printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", current->comm, current->pid, flags, __builtin_return_address(0), userRegisters[15]); #endif + /* Keep SoftFloat exception flags up to date. */ float_exception_flags |= flags; - if (readFPSR() & (flags << 16)) - { - /* raise exception */ + + /* Read fpsr and initialize the cumulativeTraps. */ + fpsr = readFPSR(); + cumulativeTraps = 0; + + /* For each type of exception, the cumulative trap exception bit is only + set if the corresponding trap enable bit is not set. */ + if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) + cumulativeTraps |= BIT_IXC; + if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) + cumulativeTraps |= BIT_UFC; + if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) + cumulativeTraps |= BIT_OFC; + if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) + cumulativeTraps |= BIT_DZC; + if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) + cumulativeTraps |= BIT_IOC; + + /* Set the cumulative exceptions flags. */ + if (cumulativeTraps) + writeFPSR(fpsr | cumulativeTraps); + + /* Raise an exception if necessary. */ + if (fpsr & (flags << 16)) fp_send_sig(SIGFPE, current, 1); - } - else - { - /* set the cumulative exceptions flags */ - writeFPSR(flags); - } } module_init(fpe_init); diff --git a/arch/arm/nwfpe/fpsr.h b/arch/arm/nwfpe/fpsr.h index f40f3872c..6dafb0f52 100644 --- a/arch/arm/nwfpe/fpsr.h +++ b/arch/arm/nwfpe/fpsr.h @@ -63,12 +63,12 @@ typedef unsigned int FPCR; /* type for floating point control register */ #define MASK_SYSTEM_CONTROL 0x0000ff00 #define MASK_TRAP_STRICT 0x00001f00 -#define BIT_AC 0x00100000 /* use alternative C-flag definition +#define BIT_AC 0x00001000 /* use alternative C-flag definition for compares */ -#define BIT_EP 0x00080000 /* use expanded packed decimal format */ -#define BIT_SO 0x00040000 /* select synchronous operation of FPA */ -#define BIT_NE 0x00020000 /* NaN exception bit */ -#define BIT_ND 0x00010000 /* no denormalized numbers bit */ +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ +#define BIT_NE 0x00000200 /* NaN exception bit */ +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ /* CUMULATIVE EXCEPTION FLAGS BYTE ---------------------------------- */ diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S index 4a9d59908..f345ea100 100644 --- a/arch/i386/boot/bootsect.S +++ b/arch/i386/boot/bootsect.S @@ -106,9 +106,8 @@ go: movw $0x4000-12, %di # 0x4000 is an arbitrary value >= pushw %ds ldsw %fs:(%bx), %si # ds:si is source movb $6, %cl # copy 12 bytes - cld pushw %di # di = 0x4000-12. - rep + rep # don't need cld -> done on line 66 movsw popw %di popw %ds @@ -140,20 +139,7 @@ load_setup: jmp load_setup ok_load_setup: -# Get disk drive parameters, specifically nr of sectors/track. - -#if 0 - -# bde - the Phoenix BIOS manual says function 0x08 only works for fixed -# disks. It doesn't work for one of my BIOS's (1987 Award). It was -# fatal not to check the error code. - - xorb %dl, %dl - movb $0x08, %ah # AH=8 is get drive parameters - int $0x13 - xorb %ch, %ch - -#else +# Get disk drive parameters, specifically number of sectors/track. # It seems that there is no BIOS call to get the number of sectors. # Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18 @@ -176,7 +162,6 @@ probe_loop: movw $0x0201, %ax # service 2, 1 sector int $0x13 jc probe_loop # try next value -#endif got_sectors: movw $INITSEG, %ax @@ -200,11 +185,11 @@ got_sectors: # Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8) # depending on the number of sectors we pretend to know we have. - movw %cs:root_dev, %ax + movw root_dev, %ax orw %ax, %ax jne root_defined - movw %cs:sectors, %bx + movw sectors, %bx movw $0x0208, %ax # /dev/ps0 - 1.2Mb cmpw $15, %bx je root_defined @@ -219,7 +204,7 @@ got_sectors: movb $0, %al # /dev/fd0 - autodetect root_defined: - movw %ax, %cs:root_dev + movw %ax, root_dev # After that (everything loaded), we jump to the setup-routine # loaded directly after the bootblock: diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 1a08bc3ab..7c50d54a8 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -436,7 +436,7 @@ no_mca: movw $0xAA, (0x1ff) # device present no_psmouse: -#ifdef CONFIG_APM +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) # Then check for an APM BIOS... # %ds points to the bootsector movw $0, 0x40 # version = 0 means no APM BIOS @@ -455,7 +455,11 @@ no_psmouse: xorw %bx, %bx int $0x15 # ignore return code movw $0x05303, %ax # 32 bit connect - xorw %bx, %bx + xorl %ebx, %ebx + xorw %cx, %cx # paranoia :-) + xorw %dx, %dx # ... + xorl %esi, %esi # ... + xorw %di, %di # ... int $0x15 jc no_32_apm_bios # Ack, error. @@ -463,12 +467,13 @@ no_psmouse: movl %ebx, (68) # BIOS entry point offset movw %cx, (72) # BIOS 16 bit code segment movw %dx, (74) # BIOS data segment - movl %esi, (78) # BIOS code segment length + movl %esi, (78) # BIOS code segment lengths movw %di, (82) # BIOS data segment length # Redo the installation check as the 32 bit connect # modifies the flags returned on some BIOSs movw $0x05300, %ax # APM BIOS installation check xorw %bx, %bx + xorw %cx, %cx # paranoia int $0x15 jc apm_disconnect # error -> shouldn't happen diff --git a/arch/i386/config.in b/arch/i386/config.in index 2377c24b7..e074ea81d 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -49,6 +49,10 @@ if [ "$CONFIG_MK7" = "y" ]; then define_bool CONFIG_X86_USE_3DNOW y fi +if [ "$CONFIG_PROC_FS" = "y" ]; then + tristate '/proc/driver/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +fi + choice 'High Memory Support' \ "off CONFIG_NOHIGHMEM \ 4GB CONFIG_HIGHMEM4G \ @@ -144,7 +148,7 @@ if [ "$CONFIG_ACPI" != "n" ]; then fi fi -bool 'Advanced Power Management BIOS support' CONFIG_APM +tristate 'Advanced Power Management BIOS support' CONFIG_APM if [ "$CONFIG_APM" != "n" ]; then bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE @@ -154,7 +158,6 @@ if [ "$CONFIG_APM" != "n" ]; then bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS - bool ' Entry point offset fix (some Acer laptops)' CONFIG_APM_BAD_ENTRY_OFFSET bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi diff --git a/arch/i386/defconfig b/arch/i386/defconfig index fcc962a11..4ca545255 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -27,6 +27,7 @@ CONFIG_X86_POPAD_OK=y CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y +# CONFIG_MICROCODE is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set @@ -175,7 +176,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set -CONFIG_ST_EXTRA_DEVS=2 # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -238,6 +238,11 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_ULTRASTOR is not set # +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA is not set + +# # I2O device support # # CONFIG_I2O is not set @@ -270,15 +275,15 @@ CONFIG_NET_ETHERNET=y # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set # CONFIG_TULIP is not set # CONFIG_DGRS is not set -CONFIG_EEXPRESS_PRO100=y +CONFIG_EEPRO100=y # CONFIG_NE2K_PCI is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set @@ -324,7 +329,6 @@ CONFIG_PCMCIA_PCNET=y # CONFIG_ARCNET_COM20020_CS is not set # CONFIG_PCMCIA_3C575 is not set # CONFIG_PCMCIA_TULIP is not set -# CONFIG_PCMCIA_EPIC100 is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y # CONFIG_PCMCIA_NETWAVE is not set @@ -423,7 +427,7 @@ CONFIG_PCMCIA_SERIAL=y # # -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set @@ -442,20 +446,17 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 96be4dff6..3b7bb1258 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -40,6 +40,16 @@ else endif endif +ifeq ($(CONFIG_PROC_FS),y) +ifeq ($(CONFIG_MICROCODE),y) +OX_OBJS += microcode.o +else + ifeq ($(CONFIG_MICROCODE),m) + MX_OBJS += microcode.o + endif +endif +endif + ifeq ($(CONFIG_ACPI),y) O_OBJS += acpi.o else diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 8ae8bc299..9bdd111d1 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -643,6 +643,7 @@ const static struct {NULL,}, {acpi_init_piix4}, {acpi_init_via}, + {acpi_init_via}, }; const static struct pci_device_id acpi_pci_tbl[] = diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index b8bca05c6..a5f72548f 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -3,6 +3,8 @@ * * (c) 1999, 2000 Ingo Molnar <mingo@redhat.com> * + * Fixes + * Maciej W. Rozycki : Bits for genuine 82489DX timers */ #include <linux/config.h> diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 81a813b05..4ec5e7993 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) * * Initial development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -35,6 +35,8 @@ * Jan 1999, Version 1.9 * Oct 1999, Version 1.10 * Nov 1999, Version 1.11 + * Jan 2000, Version 1.12 + * Feb 2000, Version 1.13 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -54,7 +56,7 @@ * The new replacment for it is, but Linux doesn't yet support this. * Alan Cox Linux 2.1.55 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's - * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by + * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by * Dean Gaudet <dgaudet@arctic.org>. * C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87 * 1.5: Fix segment register reloading (in case of bad segments saved @@ -110,6 +112,26 @@ * (reported by Panos Katsaloulis <teras@writeme.com>). * Real mode power off patch (Walter Hofmann * <Walter.Hofmann@physik.stud.uni-erlangen.de>). + * 1.12: Remove CONFIG_SMP as the compiler will optimize + * the code away anyway (smp_num_cpus == 1 in UP) + * noted by Artur Skawina <skawina@geocities.com>. + * Make power off under SMP work again. + * Fix thinko with initial engaging of BIOS. + * Make sure power off only happens on CPU 0 + * (Paul "Rusty" Russell <rusty@linuxcare.com>). + * Do error notification to user mode if BIOS calls fail. + * Move entrypoint offset fix to ...boot/setup.S + * where it belongs (Cosmos <gis88564@cis.nctu.edu.tw>). + * Remove smp-power-off. SMP users must now specify + * "apm=power-off" on the kernel command line. Suggested + * by Jim Avera <jima@hal.com>, modified by Alan Cox + * <alan@lxorguk.ukuu.org.uk>. + * Register the /proc/apm entry even on SMP so that + * scripts that check for it before doing power off + * work (Jim Avera <jima@hal.com>). + * 1.13: Changes for new pm_ interfaces (Andy Henroid + * <andy_henroid@yahoo.com>). + * Modularize the code. * * APM 1.1 Reference: * @@ -145,13 +167,12 @@ #include <linux/apm_bios.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/pm.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/desc.h> -#include <linux/pm.h> - extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); @@ -172,10 +193,10 @@ extern int (*console_blank_hook)(int); * See Documentation/Config.help for the configuration options. * * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) * apm=on/off enable/disable APM * [no-]debug log some debugging messages - * [no-]power-off power off on shutdown - * [no-]smp-power-off allow power off even for SMP + * [no-]power[-_]off power off on shutdown */ /* KNOWN PROBLEM MACHINES: @@ -219,8 +240,8 @@ extern int (*console_blank_hook)(int); /* * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. - * This patched by Chad Miller <cmiller@surfsouth.com>, orig code by David - * Chen <chen@ctpa04.mit.edu> + * This patched by Chad Miller <cmiller@surfsouth.com>, original code by + * David Chen <chen@ctpa04.mit.edu> */ #undef INIT_TIMER_AFTER_SUSPEND @@ -237,7 +258,7 @@ extern int (*console_blank_hook)(int); /* * If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then - * ignore suspend events for this amount of time + * ignore suspend events for this amount of time after a resume */ #define BOUNCE_INTERVAL (3 * HZ) @@ -248,14 +269,40 @@ extern int (*console_blank_hook)(int); __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) /* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; + int standbys_pending; + int suspends_read; + int standbys_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* * Local variables */ static struct { unsigned long offset; unsigned short segment; } apm_bios_entry; -static int apm_enabled = 0; -static int smp_hack = 0; #ifdef CONFIG_APM_CPU_IDLE static int clock_slowed = 0; #endif @@ -274,12 +321,19 @@ static int got_clock_diff = 0; #endif static int debug = 0; static int apm_disabled = 0; -static int power_off_enabled = 1; +#ifdef CONFIG_SMP +static int power_off = 0; +#else +static int power_off = 1; +#endif +static int exit_kapmd = 0; +static int kapmd_running = 0; static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static struct apm_bios_struct * user_list = NULL; +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +static struct apm_user * user_list = NULL; -static char driver_version[] = "1.11"; /* no spaces */ +static char driver_version[] = "1.12"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -380,6 +434,10 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, __save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -413,10 +471,14 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) { int cx, dx, si; + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -499,6 +561,7 @@ static void apm_do_busy(void) } } +#if 0 extern int hlt_counter; /* @@ -543,48 +606,63 @@ static void apm_cpu_idle(void) } } #endif +#endif + +#ifdef CONFIG_SMP +static int apm_magic(void * unused) +{ + while (1) + schedule(); +} +#endif static void apm_power_off(void) { +#ifdef CONFIG_APM_REAL_MODE_POWER_OFF + unsigned char po_bios_call[] = { + 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ + 0x8e, 0xd0, /* movw ax,ss */ + 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ + 0xb8, 0x07, 0x53, /* movw $0x5307,ax */ + 0xbb, 0x01, 0x00, /* movw $0x0001,bx */ + 0xb9, 0x03, 0x00, /* movw $0x0003,cx */ + 0xcd, 0x15 /* int $0x15 */ + }; +#endif + /* - * smp_hack == 2 means that we would have enabled APM support - * except there is more than one processor and so most of - * the APM stuff is unsafe. We will still try power down - * because is is useful to some people and they know what - * they are doing because they booted with the smp-power-off - * kernel option. + * This may be called on an SMP machine. */ - if (apm_enabled || (smp_hack == 2)) { +#ifdef CONFIG_SMP + /* Some bioses don't like being called from CPU != 0 */ + while (cpu_number_map[smp_processor_id()] != 0) { + kernel_thread(apm_magic, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + schedule(); + } +#endif #ifdef CONFIG_APM_REAL_MODE_POWER_OFF - unsigned char po_bios_call[] = { - 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ - 0x8e, 0xd0, /* movw ax,ss */ - 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ - 0xb8, 0x07, 0x53, /* movw $0x5307,ax */ - 0xbb, 0x01, 0x00, /* movw $0x0001,bx */ - 0xb9, 0x03, 0x00, /* movw $0x0003,cx */ - 0xcd, 0x15 /* int $0x15 */ - }; - - machine_real_restart(po_bios_call, sizeof(po_bios_call)); + machine_real_restart(po_bios_call, sizeof(po_bios_call)); #else - (void) apm_set_power_state(APM_STATE_OFF); + (void) apm_set_power_state(APM_STATE_OFF); #endif - } } -#ifdef CONFIG_APM_DO_ENABLE -static int __init apm_enable_power_management(void) +static int apm_enable_power_management(int enable) { u32 eax; + if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED)) + return APM_NOT_ENGAGED; if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL, - 1, &eax)) + enable, &eax)) return (eax >> 8) & 0xff; - apm_bios_info.flags &= ~APM_BIOS_DISABLED; + if (enable) + apm_bios_info.flags &= ~APM_BIOS_DISABLED; + else + apm_bios_info.flags |= APM_BIOS_DISABLED; return APM_SUCCESS; } -#endif static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) { @@ -632,12 +710,21 @@ static int apm_get_battery_status(u_short which, u_short *status, } #endif -static int __init apm_engage_power_management(u_short device) +static int apm_engage_power_management(u_short device, int enable) { u32 eax; - if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, 1, &eax)) + if ((enable == 0) && (device == APM_DEVICE_ALL) + && (apm_bios_info.flags & APM_BIOS_DISABLED)) + return APM_DISABLED; + if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax)) return (eax >> 8) & 0xff; + if (device == APM_DEVICE_ALL) { + if (enable) + apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + else + apm_bios_info.flags |= APM_BIOS_DISENGAGED; + } return APM_SUCCESS; } @@ -655,7 +742,6 @@ static void apm_error(char *str, int err) } #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) -/* Called from console driver -- must make sure apm_enabled. */ static int apm_console_blank(int blank) { int error; @@ -664,9 +750,13 @@ static int apm_console_blank(int blank) state = blank ? APM_STATE_STANDBY : APM_STATE_READY; /* Blank the first display device */ error = set_power_state(0x100, state); - if (error != APM_SUCCESS) + if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) { /* try to blank them all instead */ error = set_power_state(0x1ff, state); + if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) + /* try to blank device one instead */ + error = set_power_state(0x101, state); + } if ((error == APM_SUCCESS) || (error == APM_NO_ERROR)) return 1; apm_error("set display", error); @@ -674,20 +764,20 @@ static int apm_console_blank(int blank) } #endif -static int queue_empty(struct apm_bios_struct * as) +static int queue_empty(struct apm_user *as) { return as->event_head == as->event_tail; } -static apm_event_t get_queued_event(struct apm_bios_struct * as) +static apm_event_t get_queued_event(struct apm_user *as) { as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; return as->events[as->event_tail]; } -static void queue_event(apm_event_t event, struct apm_bios_struct *sender) +static void queue_event(apm_event_t event, struct apm_user *sender) { - struct apm_bios_struct * as; + struct apm_user * as; if (user_list == NULL) return; @@ -751,18 +841,11 @@ static void get_time_diff(void) #endif } -static void suspend(void) +static void reinit_timer(void) { - int err; #ifdef INIT_TIMER_AFTER_SUSPEND unsigned long flags; -#endif - get_time_diff(); - err = apm_set_power_state(APM_STATE_SUSPEND); - if ((err != APM_SUCCESS) && (err != APM_NO_ERROR)) - apm_error("suspend", err); -#ifdef INIT_TIMER_AFTER_SUSPEND save_flags(flags); cli(); /* set the clock to 100 Hz */ @@ -774,7 +857,27 @@ static void suspend(void) udelay(10); restore_flags(flags); #endif +} + +static int suspend(void) +{ + int err; + int ret; + struct apm_user *as; + + get_time_diff(); + err = apm_set_power_state(APM_STATE_SUSPEND); + reinit_timer(); set_time(); + ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR); + if (!ret) + apm_error("suspend", err); + for (as = user_list; as != NULL; as = as->next) { + as->suspend_wait = 0; + as->suspend_result = (ret ? 0 : -EIO); + } + wake_up_interruptible(&apm_suspend_waitqueue); + return ret; } static void standby(void) @@ -806,15 +909,14 @@ static apm_event_t get_event(void) return 0; } -static int send_event(apm_event_t event, apm_event_t undo, - struct apm_bios_struct *sender) +static int send_event(apm_event_t event, struct apm_user *sender) { switch (event) { case APM_SYS_SUSPEND: case APM_CRITICAL_SUSPEND: case APM_USER_SUSPEND: /* map all suspends to ACPI D3 */ - if (pm_send_request(PM_SUSPEND, (void*) 3)) { + if (pm_send_request(PM_SUSPEND, (void *)3)) { if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; @@ -823,11 +925,7 @@ static int send_event(apm_event_t event, apm_event_t undo, case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: /* map all resumes to ACPI D0 */ - if (pm_send_request(PM_RESUME, 0)) { - if (apm_bios_info.version > 0x100) - apm_set_power_state(APM_STATE_REJECT); - return 0; - } + (void) pm_send_request(PM_RESUME, (void *)0); break; } @@ -864,7 +962,7 @@ static void check_events(void) if (waiting_for_resume) break; #endif - if (send_event(event, APM_STANDBY_RESUME, NULL)) { + if (send_event(event, NULL)) { #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 1; #endif @@ -888,12 +986,12 @@ static void check_events(void) if (waiting_for_resume) break; #endif - if (send_event(event, APM_NORMAL_RESUME, NULL)) { + if (send_event(event, NULL)) { #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 1; #endif if (suspends_pending <= 0) - suspend(); + (void) suspend(); } break; @@ -908,13 +1006,13 @@ static void check_events(void) ignore_bounce = 1; #endif set_time(); - send_event(event, 0, NULL); + send_event(event, NULL); break; case APM_CAPABILITY_CHANGE: case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: - send_event(event, 0, NULL); + send_event(event, NULL); break; case APM_UPDATE_TIME: @@ -922,7 +1020,7 @@ static void check_events(void) break; case APM_CRITICAL_SUSPEND: - suspend(); + (void) suspend(); break; } } @@ -930,18 +1028,18 @@ static void check_events(void) static void apm_event_handler(void) { - static int pending_count = 0; + static int pending_count = 4; int err; if ((standbys_pending > 0) || (suspends_pending > 0)) { - if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) { + if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) { pending_count = 4; err = apm_set_power_state(APM_STATE_BUSY); if (err) apm_error("busy", err); } } else - pending_count = 0; + pending_count = 4; check_events(); } @@ -957,13 +1055,17 @@ static void apm_event_handler(void) static void apm_mainloop(void) { DECLARE_WAITQUEUE(wait, current); - apm_enabled = 1; + + if (smp_num_cpus > 1) + return; add_wait_queue(&apm_waitqueue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { /* Nothing to do, just sleep for the timeout */ schedule_timeout(APM_CHECK_TIMEOUT); + if (exit_kapmd) + break; /* * Ok, check all events, check for idle (and mark us sleeping @@ -976,11 +1078,11 @@ static void apm_mainloop(void) continue; if (apm_do_idle()) { unsigned long start = jiffies; - do { + while (system_idle()) { apm_do_idle(); if (jiffies - start > APM_CHECK_TIMEOUT) break; - } while (system_idle()); + } apm_do_busy(); apm_event_handler(); } @@ -988,7 +1090,7 @@ static void apm_mainloop(void) } } -static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func) +static int check_apm_user(struct apm_user *as, const char *func) { if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { printk(KERN_ERR "apm: %s passed bad filp", func); @@ -999,13 +1101,13 @@ static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func) static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) { - struct apm_bios_struct * as; + struct apm_user * as; int i; apm_event_t event; DECLARE_WAITQUEUE(wait, current); as = fp->private_data; - if (check_apm_bios_struct(as, "read")) + if (check_apm_user(as, "read")) return -EIO; if (count < sizeof(apm_event_t)) return -EINVAL; @@ -1053,10 +1155,10 @@ repeat: static unsigned int do_poll(struct file *fp, poll_table * wait) { - struct apm_bios_struct * as; + struct apm_user * as; as = fp->private_data; - if (check_apm_bios_struct(as, "select")) + if (check_apm_user(as, "poll")) return 0; poll_wait(fp, &apm_waitqueue, wait); if (!queue_empty(as)) @@ -1067,11 +1169,11 @@ static unsigned int do_poll(struct file *fp, poll_table * wait) static int do_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { - struct apm_bios_struct * as; - int send_ok = 1; + struct apm_user * as; + DECLARE_WAITQUEUE(wait, current); as = filp->private_data; - if (check_apm_bios_struct(as, "ioctl")) + if (check_apm_user(as, "ioctl")) return -EIO; if (!as->suser) return -EPERM; @@ -1081,11 +1183,9 @@ static int do_ioctl(struct inode * inode, struct file *filp, as->standbys_read--; as->standbys_pending--; standbys_pending--; - } - else - send_ok = send_event(APM_USER_STANDBY, - APM_STANDBY_RESUME, as); - if (send_ok && (standbys_pending <= 0)) + } else if (!send_event(APM_USER_STANDBY, as)) + return -EAGAIN; + if (standbys_pending <= 0) standby(); break; case APM_IOC_SUSPEND: @@ -1093,12 +1193,25 @@ static int do_ioctl(struct inode * inode, struct file *filp, as->suspends_read--; as->suspends_pending--; suspends_pending--; + } else if (!send_event(APM_USER_SUSPEND, as)) + return -EAGAIN; + if (suspends_pending <= 0) { + if (!suspend()) + return -EIO; + } else { + as->suspend_wait = 1; + add_wait_queue(&apm_suspend_waitqueue, &wait); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + if ((as->suspend_wait == 0) + || signal_pending(current)) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&apm_suspend_waitqueue, &wait); + return as->suspend_result; } - else - send_ok = send_event(APM_USER_SUSPEND, - APM_NORMAL_RESUME, as); - if (send_ok && (suspends_pending <= 0)) - suspend(); break; default: return -EINVAL; @@ -1108,10 +1221,10 @@ static int do_ioctl(struct inode * inode, struct file *filp, static int do_release(struct inode * inode, struct file * filp) { - struct apm_bios_struct * as; + struct apm_user * as; as = filp->private_data; - if (check_apm_bios_struct(as, "release")) + if (check_apm_user(as, "release")) return 0; filp->private_data = NULL; if (as->standbys_pending > 0) { @@ -1122,12 +1235,12 @@ static int do_release(struct inode * inode, struct file * filp) if (as->suspends_pending > 0) { suspends_pending -= as->suspends_pending; if (suspends_pending <= 0) - suspend(); + (void) suspend(); } if (user_list == as) user_list = as->next; else { - struct apm_bios_struct * as1; + struct apm_user * as1; for (as1 = user_list; (as1 != NULL) && (as1->next != as); @@ -1139,17 +1252,21 @@ static int do_release(struct inode * inode, struct file * filp) as1->next = as->next; } kfree_s(as, sizeof(*as)); + MOD_DEC_USE_COUNT; return 0; } static int do_open(struct inode * inode, struct file * filp) { - struct apm_bios_struct * as; + struct apm_user * as; - as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL); + MOD_INC_USE_COUNT; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); if (as == NULL) { printk(KERN_ERR "apm: cannot allocate struct of size %d bytes", sizeof(*as)); + MOD_DEC_USE_COUNT; return -ENOMEM; } as->magic = APM_BIOS_MAGIC; @@ -1184,11 +1301,10 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) int time_units = -1; char *units = "?"; - if (!apm_enabled) - return 0; p = buf; - if (!(error = apm_get_power_status(&bx, &cx, &dx))) { + if ((smp_num_cpus == 1) && + !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; if ((cx & 0xff) != 0xff) @@ -1264,6 +1380,11 @@ static int apm(void *unused) char * power_stat; char * bat_stat; + kapmd_running = 1; + + exit_files(current); /* daemonize doesn't do exit_files */ + daemonize(); + strcpy(current->comm, "kapmd"); sigfillset(¤t->blocked); @@ -1278,7 +1399,7 @@ static int apm(void *unused) apm_bios_info.version = 0x100; } } - if (debug) { + if (debug && (smp_num_cpus == 1)) { printk(KERN_INFO "apm: Connection version %d.%d\n", (apm_bios_info.version >> 8) & 0xff, apm_bios_info.version & 0xff); @@ -1328,32 +1449,51 @@ static int apm(void *unused) * is booted with PM disabled but not in the docking station. * Unfortunate ... */ - error = apm_enable_power_management(); + error = apm_enable_power_management(1); if (error) { apm_error("enable power management", error); return -1; } } #endif - if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0) + if ((apm_bios_info.flags & APM_BIOS_DISENGAGED) && (apm_bios_info.version > 0x0100)) { - if (apm_engage_power_management(0x0001) == APM_SUCCESS) - apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + error = apm_engage_power_management(APM_DEVICE_ALL, 1); + if (error) { + apm_error("engage power management", error); + return -1; + } } /* Install our power off handler.. */ - if (power_off_enabled) + if (power_off) pm_power_off = apm_power_off; #ifdef CONFIG_MAGIC_SYSRQ sysrq_power_off = apm_power_off; #endif #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) - console_blank_hook = apm_console_blank; + if (smp_num_cpus == 1) + console_blank_hook = apm_console_blank; #endif pm_active = 1; apm_mainloop(); + + pm_active = 0; + +#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) + if (smp_num_cpus == 1) + console_blank_hook = NULL; +#endif +#ifdef CONFIG_MAGIC_SYSRQ + sysrq_power_off = NULL; +#endif + if (power_off) + pm_power_off = NULL; + + kapmd_running = 0; + return 0; } @@ -1371,10 +1511,9 @@ static int __init apm_setup(char *str) str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; - if (strncmp(str, "power-off", 9) == 0) - power_off_enabled = !invert; - if (strncmp(str, "smp-power-off", 13) == 0) - smp_hack = !invert; + if ((strncmp(str, "power-off", 9) == 0) || + (strncmp(str, "power_off", 9) == 0)) + power_off = !invert; str = strchr(str, ','); if (str != NULL) str += strspn(str, ", \t"); @@ -1394,7 +1533,7 @@ static struct file_operations apm_bios_fops = { static struct miscdevice apm_device = { APM_MINOR_DEV, - "apm", + "apm_bios", &apm_bios_fops }; @@ -1455,7 +1594,10 @@ static int __init apm_init(void) printk(KERN_NOTICE "apm: disabled on user request.\n"); APM_INIT_ERROR_RETURN; } - + if ((smp_num_cpus > 1) && !power_off) { + printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + APM_INIT_ERROR_RETURN; + } if (PM_IS_ACTIVE()) { printk(KERN_NOTICE "apm: overridden by ACPI.\n"); APM_INIT_ERROR_RETURN; @@ -1472,9 +1614,6 @@ static int __init apm_init(void) _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); apm_bios_entry.offset = apm_bios_info.offset; -#ifdef CONFIG_APM_BAD_ENTRY_OFFSET - apm_bios_entry.offset &= 0xffff; -#endif apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], __va((unsigned long)apm_bios_info.cseg << 4)); @@ -1483,18 +1622,16 @@ static int __init apm_init(void) set_base(gdt[APM_DS >> 3], __va((unsigned long)apm_bios_info.dseg << 4)); #ifndef APM_RELAX_SEGMENTS - if (apm_bios_info.version == 0x100) + if (apm_bios_info.version == 0x100) { #endif - { /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1); - } #ifndef APM_RELAX_SEGMENTS - else { + } else { _set_limit((char *)&gdt[APM_CS >> 3], (apm_bios_info.cseg_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_CS_16 >> 3], @@ -1504,21 +1641,36 @@ static int __init apm_init(void) } #endif -#ifdef CONFIG_SMP + create_proc_info_entry("apm", 0, NULL, apm_get_info); + + kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + if (smp_num_cpus > 1) { - printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - if (smp_hack) - smp_hack = 2; + printk(KERN_NOTICE + "apm: disabled - APM is not SMP safe (power off active).\n"); APM_INIT_ERROR_RETURN; } -#endif - - create_proc_info_entry("apm", 0, 0, apm_get_info); misc_register(&apm_device); - kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); return 0; } -__initcall(apm_init); +static void __exit apm_exit(void) +{ + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + exit_kapmd = 1; + while (kapmd_running) + schedule(); +} + +module_init(apm_init); +module_exit(apm_exit); + +MODULE_AUTHOR("Stephen Rothwell"); +MODULE_DESCRIPTION("Advanced Power Management"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Enable debug mode"); + +EXPORT_NO_SYMBOLS; diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index f58e7485f..cad6ceb17 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -10,6 +10,7 @@ #include <linux/smp_lock.h> #include <linux/pm.h> #include <linux/pci.h> +#include <linux/apm_bios.h> #include <asm/semaphore.h> #include <asm/processor.h> @@ -20,6 +21,7 @@ #include <asm/delay.h> #include <asm/irq.h> #include <asm/mmx.h> +#include <asm/desc.h> extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -34,6 +36,8 @@ extern struct drive_info_struct drive_info; EXPORT_SYMBOL(drive_info); #endif +extern unsigned long get_cmos_time(void); + /* platform dependent support */ EXPORT_SYMBOL(boot_cpu_data); EXPORT_SYMBOL(EISA_bus); @@ -51,6 +55,9 @@ EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); +EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(apm_bios_info); +EXPORT_SYMBOL(gdt); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index c62e5c2d2..d54f9b503 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -311,7 +311,7 @@ spurious_8259A_irq: } } -void init_8259A(int auto_eoi) +void __init init_8259A(int auto_eoi) { unsigned long flags; @@ -384,7 +384,7 @@ static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; #endif -void init_ISA_irqs (void) +void __init init_ISA_irqs (void) { int i; diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 0037bebdd..75b2bfb9f 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -11,6 +11,9 @@ * Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>, * further tested and cleaned up by Zach Brown <zab@redhat.com> * and Ingo Molnar <mingo@redhat.com> + * + * Fixes + * Maciej W. Rozycki : Bits for genuine 82489DX APICs */ #include <linux/mm.h> @@ -249,7 +252,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) best_guess = irq; } } - return -1; + return best_guess; } /* @@ -906,40 +909,6 @@ void disable_IO_APIC(void) } } -static void __init setup_ioapic_default_id(void) -{ - struct IO_APIC_reg_00 reg_00; - - /* - * 'default' mptable configurations mean a hardwired setup, - * 2 CPUs, 16 APIC registers. IO-APIC ID is usually set to 0, - * setting it to ID 2 should be fine. - */ - - /* - * Sanity check, is ID 2 really free? Every APIC in the - * system must have a unique ID or we get lots of nice - * 'stuck on smp_invalidate_needed IPI wait' messages. - */ - if (phys_cpu_present_map & (1<<0x2)) - panic("APIC ID 2 already used"); - - /* - * Set the ID - */ - *(int *)®_00 = io_apic_read(0, 0); - printk("...changing IO-APIC physical APIC ID to 2...\n"); - reg_00.ID = 0x2; - io_apic_write(0, 0, *(int *)®_00); - - /* - * Sanity check - */ - *(int *)®_00 = io_apic_read(0, 0); - if (reg_00.ID != 0x2) - panic("could not set ID"); -} - /* * function to set the IO-APIC physical IDs based on the * values stored in the MPC table. @@ -967,6 +936,15 @@ static void __init setup_ioapic_ids_from_mpc (void) printk("...changing IO-APIC physical APIC ID to %d ...", mp_ioapics[apic].mpc_apicid); + /* + * Sanity check, is the ID really free? Every APIC in the + * system must have a unique ID or we get lots of nice + * 'stuck on smp_invalidate_needed IPI wait' messages. + */ + if (phys_cpu_present_map & (1<<mp_ioapics[apic].mpc_apicid)) + panic("APIC ID %d already used", + mp_ioapics[apic].mpc_apicid); + reg_00.ID = mp_ioapics[apic].mpc_apicid; io_apic_write(apic, 0, *(int *)®_00); @@ -1021,7 +999,6 @@ static void __init construct_default_ISA_mptable(void) mp_irqs[0].mpc_dstirq = 2; } - setup_ioapic_default_id(); } /* @@ -1264,6 +1241,7 @@ static inline void check_timer(void) /* * get/set the timer IRQ vector: */ + disable_8259A_irq(0); vector = assign_irq_vector(0); set_intr_gate(vector, interrupt[0]); @@ -1390,7 +1368,6 @@ void IO_APIC_init_uniprocessor (void) { if (!smp_found_config) return; - phys_cpu_present_map = 0xff; setup_local_APIC(); setup_IO_APIC(); setup_APIC_clocks(); diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 6112ac036..9d4a81041 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -713,6 +713,7 @@ unsigned long probe_irq_on(void) if (!(status & IRQ_WAITING)) { irq_desc[i].status = status & ~IRQ_AUTODETECT; irq_desc[i].handler->shutdown(i); + continue; } if (i < 32) diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c new file mode 100644 index 000000000..26b6525d8 --- /dev/null +++ b/arch/i386/kernel/microcode.c @@ -0,0 +1,266 @@ +/* + * CPU Microcode Update interface for Linux + * + * Copyright (C) 2000 Tigran Aivazian + * + * This driver allows to upgrade microcode on Intel processors + * belonging to P6 family - PentiumPro, Pentium II, Pentium III etc. + * + * Reference: Section 8.10 of Volume III, Intel Pentium III Manual, + * Order Number 243192 or download from: + * + * http://developer.intel.com/design/pentiumii/manuals/243192.htm + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 1.0 16 February 2000, Tigran Aivazian <tigran@sco.com> + * Initial release. + * 1.01 18 February 2000, Tigran Aivazian <tigran@sco.com> + * Added read() support + cleanups. + */ + +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/smp_lock.h> +#include <linux/proc_fs.h> + +#include <asm/msr.h> +#include <asm/uaccess.h> +#include <asm/processor.h> + +#define MICROCODE_VERSION "1.01" + +MODULE_DESCRIPTION("CPU (P6) microcode update driver"); +MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>"); +EXPORT_NO_SYMBOLS; + +/* VFS interface */ +static int microcode_open(struct inode *, struct file *); +static int microcode_release(struct inode *, struct file *); +static ssize_t microcode_read(struct file *, char *, size_t, loff_t *); +static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *); + + +/* internal helpers to do the work */ +static int do_microcode_update(void); +static void do_update_one(void *); + +/* + * Bits in microcode_status. (31 bits of room for future expansion) + */ +#define MICROCODE_IS_OPEN 0 /* set if /dev/microcode is in use */ +static unsigned long microcode_status = 0; + +/* the actual array of microcode blocks, each 2048 bytes */ +static struct microcode * microcode = NULL; +static unsigned int microcode_num = 0; +static char *mc_applied = NULL; /* holds an array of applied microcode blocks */ + +static struct file_operations microcode_fops = { + read: microcode_read, + write: microcode_write, + open: microcode_open, + release: microcode_release, +}; + +static struct inode_operations microcode_inops = { + default_file_ops: µcode_fops, +}; + +static struct proc_dir_entry *proc_microcode; + +static int __init microcode_init(void) +{ + int size; + + proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver); + if (!proc_microcode) { + printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n"); + return -ENOMEM; + } + proc_microcode->ops = µcode_inops; + size = smp_num_cpus * sizeof(struct microcode); + mc_applied = kmalloc(size, GFP_KERNEL); + if (!mc_applied) { + remove_proc_entry("microcode", proc_root_driver); + printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); + return -ENOMEM; + } + memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed + update makes this obvious */ + printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); + return 0; +} + +static void __exit microcode_exit(void) +{ + remove_proc_entry("microcode", proc_root_driver); + kfree(mc_applied); + printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); +} + +module_init(microcode_init); +module_exit(microcode_exit); + +/* + * We enforce only one user at a time here with open/close. + */ +static int microcode_open(struct inode *inode, struct file *file) +{ + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* one at a time, please */ + if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) + return -EBUSY; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int microcode_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + + clear_bit(MICROCODE_IS_OPEN, µcode_status); + return 0; +} + +/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one() + * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise + * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode + */ +struct update_req { + int err; + int slot; +} update_req[NR_CPUS]; + +static int do_microcode_update(void) +{ + int i, error = 0, err; + struct microcode *m; + + if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0) + panic("do_microcode_update(): timed out waiting for other CPUs\n"); + do_update_one((void *)update_req); + + for (i=0; i<smp_num_cpus; i++) { + err = update_req[i].err; + error += err; + if (!err) { + m = (struct microcode *)mc_applied + i; + memcpy(m, µcode[update_req[i].slot], sizeof(struct microcode)); + } + } + return error ? -EIO : 0; +} + +static void do_update_one(void *arg) +{ + struct update_req *req; + struct cpuinfo_x86 * c; + unsigned int pf = 0, val[2], rev, sig; + int i, cpu_num; + + cpu_num = smp_processor_id(); + c = cpu_data + cpu_num; + req = (struct update_req *)arg + cpu_num; + req->err = 1; /* be pessimistic */ + + if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6) + return; + + sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8); + + if (c->x86_model >= 5) { + /* get processor flags from BBL_CR_OVRD MSR (0x17) */ + rdmsr(0x17, val[0], val[1]); + pf = 1 << ((val[1] >> 18) & 7); + } + + for (i=0; i<microcode_num; i++) + if (microcode[i].sig == sig && microcode[i].pf == pf && + microcode[i].ldrver == 1 && microcode[i].hdrver == 1) { + + rdmsr(0x8B, val[0], rev); + if (microcode[i].rev <= rev) { + printk(KERN_ERR + "microcode: CPU%d not 'upgrading' to earlier revision" + " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); + } else { + int sum = 0; + struct microcode *m = µcode[i]; + unsigned int *sump = (unsigned int *)(m+1); + + while (--sump >= (unsigned int *)m) + sum += *sump; + if (sum != 0) { + printk(KERN_ERR "microcode: CPU%d aborting, " + "bad checksum\n", cpu_num); + break; + } + + wrmsr(0x79, (unsigned int)(m->bits), 0); + __asm__ __volatile__ ("cpuid"); + rdmsr(0x8B, val[0], val[1]); + + req->err = 0; + req->slot = i; + printk(KERN_ERR "microcode: CPU%d microcode updated " + "from revision %d to %d, date=%08x\n", + cpu_num, rev, val[1], m->date); + } + break; + } +} + +static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) +{ + size_t fsize = smp_num_cpus * sizeof(struct microcode); + + if (!proc_microcode->size || *ppos >= fsize) + return 0; /* EOF */ + if (*ppos + len > fsize) + len = fsize - *ppos; + if (copy_to_user(buf, mc_applied + *ppos, len)) + return -EFAULT; + *ppos += len; + return len; +} + +static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos) +{ + ssize_t ret; + + if (len % sizeof(struct microcode) != 0) { + printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", + sizeof(struct microcode)); + return -EINVAL; + } + lock_kernel(); + microcode_num = len/sizeof(struct microcode); + microcode = vmalloc(len); + if (!microcode) { + unlock_kernel(); + return -ENOMEM; + } + if (copy_from_user(microcode, buf, len)) { + vfree(microcode); + unlock_kernel(); + return -EFAULT; + } + ret = do_microcode_update(); + if (!ret) { + proc_microcode->size = smp_num_cpus * sizeof(struct microcode); + ret = (ssize_t)len; + } + vfree(microcode); + unlock_kernel(); + return ret; +} diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 977dd18ba..81685d2f5 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -9,7 +9,7 @@ * Erich Boleyn : MP v1.4 and additional changes. * Alan Cox : Added EBDA scanning * Ingo Molnar : various cleanups and rewrites - * Maciej W. Rozycki : Bits for genuine 82489DX timers + * Maciej W. Rozycki : Bits for genuine 82489DX APICs */ #include <linux/mm.h> @@ -339,6 +339,8 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf) * Now see if we need to read further. */ if (mpf->mpf_feature1 != 0) { + printk("Default MP configuration #%d\n", mpf->mpf_feature1); + /* * local APIC has default address */ @@ -352,6 +354,7 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf) nr_ioapics = 1; mp_ioapics[0].mpc_apicaddr = 0xFEC00000; + mp_ioapics[0].mpc_apicid = 2; /* * Save the default type number, we * need it later to set the IO-APIC diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index 5caa4e477..a0a4ab851 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -1,6 +1,6 @@ /* Generic MTRR (Memory Type Range Register) driver. - Copyright (C) 1997-1999 Richard Gooch + Copyright (C) 1997-2000 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -133,7 +133,7 @@ Fixed version numbering and history for v1.23 -> v1.24. v1.26 19990118 Richard Gooch <rgooch@atnf.csiro.au> - PLACEHOLDER. + Added devfs support. v1.27 19990123 Richard Gooch <rgooch@atnf.csiro.au> Changed locking to spin with reschedule. @@ -178,7 +178,6 @@ Moved to linux/arch/i386/kernel/setup.c and linux/include/asm-i386/bugs.h 19990228 Richard Gooch <rgooch@atnf.csiro.au> - Added #ifdef CONFIG_DEVFS_FS Added MTRRIOC_KILL_ENTRY ioctl(2) Trap for counter underflow in <mtrr_file_del>. Trap for 4 MiB aligned regions for PPro, stepping <= 7. @@ -225,6 +224,10 @@ success. 19991008 Manfred Spraul <manfreds@colorfullife.com> replaced spin_lock_reschedule() with a normal semaphore. + v1.36 + 20000221 Richard Gooch <rgooch@atnf.csiro.au> + Compile fix if procfs and devfs not enabled. + Formatting changes. */ #include <linux/types.h> #include <linux/errno.h> @@ -241,6 +244,7 @@ #include <linux/fs.h> #include <linux/ctype.h> #include <linux/proc_fs.h> +#include <linux/devfs_fs_kernel.h> #include <linux/mm.h> #include <linux/module.h> #define MTRR_NEED_STRINGS @@ -261,7 +265,7 @@ #include <asm/hardirq.h> #include <linux/irq.h> -#define MTRR_VERSION "1.35 (19990512)" +#define MTRR_VERSION "1.36 (20000221)" #define TRUE 1 #define FALSE 0 @@ -305,11 +309,15 @@ typedef u8 mtrr_type; TRUE) #endif -#ifndef CONFIG_PROC_FS +#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS) +# define USERSPACE_INTERFACE +#endif + +#ifndef USERSPACE_INTERFACE # define compute_ascii() while (0) #endif -#ifdef CONFIG_PROC_FS +#ifdef USERSPACE_INTERFACE static char *ascii_buffer = NULL; static unsigned int ascii_buf_bytes = 0; #endif @@ -317,7 +325,7 @@ static unsigned int *usage_table = NULL; static DECLARE_MUTEX(main_lock); /* Private functions */ -#ifdef CONFIG_PROC_FS +#ifdef USERSPACE_INTERFACE static void compute_ascii (void); #endif @@ -480,8 +488,9 @@ static void intel_get_mtrr (unsigned int reg, unsigned long *base, unsigned long dummy, mask_lo, base_lo; rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy); - if ((mask_lo & 0x800) == 0) { - /* Invalid (i.e. free) range. */ + if ( (mask_lo & 0x800) == 0 ) + { + /* Invalid (i.e. free) range */ *base = 0; *size = 0; *type = 0; @@ -537,22 +546,26 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base, *size = 0; /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */ - if (reg < 7) { - switch (rcr) { - case 1: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRBACK; break; - case 9: *type = MTRR_TYPE_WRCOMB; break; - case 24: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } - } else { - switch (rcr) { - case 0: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRCOMB; break; - case 9: *type = MTRR_TYPE_WRBACK; break; - case 25: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } + if (reg < 7) + { + switch (rcr) + { + case 1: *type = MTRR_TYPE_UNCACHABLE; break; + case 8: *type = MTRR_TYPE_WRBACK; break; + case 9: *type = MTRR_TYPE_WRCOMB; break; + case 24: + default: *type = MTRR_TYPE_WRTHROUGH; break; + } + } else + { + switch (rcr) + { + case 0: *type = MTRR_TYPE_UNCACHABLE; break; + case 8: *type = MTRR_TYPE_WRCOMB; break; + case 9: *type = MTRR_TYPE_WRBACK; break; + case 25: + default: *type = MTRR_TYPE_WRTHROUGH; break; + } } } /* End Function cyrix_get_arr */ @@ -653,20 +666,24 @@ static void cyrix_set_arr_up (unsigned int reg, unsigned long base, size &= 0x7fff; /* make sure arr_size <= 14 */ for(arr_size = 0; size; arr_size++, size >>= 1); - if (reg<7) { - switch (type) { - case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; - case MTRR_TYPE_WRCOMB: arr_type = 9; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; - default: arr_type = 8; break; - } - } else { - switch (type) { - case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; - case MTRR_TYPE_WRCOMB: arr_type = 8; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; - default: arr_type = 9; break; - } + if (reg<7) + { + switch (type) { + case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; + case MTRR_TYPE_WRCOMB: arr_type = 9; break; + case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; + default: arr_type = 8; break; + } + } + else + { + switch (type) + { + case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; + case MTRR_TYPE_WRCOMB: arr_type = 8; break; + case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; + default: arr_type = 9; break; + } } if (do_safe) set_mtrr_prepare (&ctxt); @@ -779,16 +796,18 @@ static int __init set_mtrr_var_range_testing (unsigned int index, int changed = FALSE; rdmsr(MTRRphysBase_MSR(index), lo, hi); - if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) - || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) + || (vr->base_hi & 0xfUL) != (hi & 0xfUL) ) + { + wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); changed = TRUE; } - rdmsr(MTRRphysMask_MSR(index), lo, hi); + rdmsr (MTRRphysMask_MSR(index), lo, hi); - if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) - || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { + if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) + || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) ) + { wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); changed = TRUE; } @@ -816,22 +835,27 @@ static int __init set_fixed_ranges_testing(mtrr_type *frs) unsigned long lo, hi; rdmsr(MTRRfix64K_00000_MSR, lo, hi); - if (p[0] != lo || p[1] != hi) { - wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + if (p[0] != lo || p[1] != hi) + { + wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); changed = TRUE; } - for (i = 0; i < 2; i++) { - rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); - if (p[2 + i*2] != lo || p[3 + i*2] != hi) { - wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); + for (i = 0; i < 2; i++) + { + rdmsr (MTRRfix16K_80000_MSR + i, lo, hi); + if (p[2 + i*2] != lo || p[3 + i*2] != hi) + { + wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); changed = TRUE; } } - for (i = 0; i < 8; i++) { - rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); - if (p[6 + i*2] != lo || p[7 + i*2] != hi) { + for (i = 0; i < 8; i++) + { + rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); + if (p[6 + i*2] != lo || p[7 + i*2] != hi) + { wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); changed = TRUE; } @@ -899,8 +923,8 @@ static unsigned long __init set_mtrr_state (struct mtrr_state *state, change_mask |= MTRR_CHANGE_MASK_FIXED; /* Set_mtrr_restore restores the old value of MTRRdefType, so to set it we fiddle with the saved value */ - if ((ctxt->deftype_lo & 0xff) != state->def_type - || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) + if ( (ctxt->deftype_lo & 0xff) != state->def_type + || ( (ctxt->deftype_lo & 0xc00) >> 10 ) != state->enabled) { ctxt->deftype_lo |= (state->def_type | state->enabled << 10); change_mask |= MTRR_CHANGE_MASK_DEFTYPE; @@ -1010,7 +1034,7 @@ static void init_table (void) return; } for (i = 0; i < max; i++) usage_table[i] = 1; -#ifdef CONFIG_PROC_FS +#ifdef USERSPACE_INTERFACE if ( ( ascii_buffer = kmalloc (max * LINE_SIZE, GFP_KERNEL) ) == NULL ) { printk ("mtrr: could not allocate\n"); @@ -1053,11 +1077,14 @@ static int cyrix_get_free_region (unsigned long base, unsigned long size) unsigned long lbase, lsize; /* If we are to set up a region >32M then look at ARR7 immediately */ - if (size > 0x2000000UL) { + if (size > 0x2000000UL) + { cyrix_get_arr (7, &lbase, &lsize, <ype); if (lsize < 1) return 7; - /* else try ARR0-ARR6 first */ - } else { + /* Else try ARR0-ARR6 first */ + } + else + { for (i = 0; i < 7; i++) { cyrix_get_arr (i, &lbase, &lsize, <ype); @@ -1095,29 +1122,32 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type, switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ - /* Apply the K6 block alignment and size rules + if (boot_cpu_data.x86 < 6) + { /* pre-Athlon CPUs */ + /* Apply the K6 block alignment and size rules In order o Uncached or gathering only o 128K or bigger block o Power of 2 block o base suitably aligned to the power */ - if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || - (size & ~(size-1))-size || (base & (size-1))) - return -EINVAL; + if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) || + (size & ~(size-1))-size || ( base & (size-1) ) ) + return -EINVAL; break; - } /* else fall through */ + } + /* Else fall through */ case X86_VENDOR_INTEL: - /* Double check for Intel, we may run on Athlon. */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { - /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ - if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && - (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) ) - { - printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); - return -EINVAL; - } + /* Double check for Intel, we may run on Athlon */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + { + /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ + if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && + (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) ) + { + printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); + return -EINVAL; + } } /* Fall through */ case X86_VENDOR_CYRIX: @@ -1232,7 +1262,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size) if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; max = get_num_var_ranges (); - down(&main_lock); + down (&main_lock); if (reg < 0) { /* Search for existing MTRR */ @@ -1254,15 +1284,15 @@ int mtrr_del (int reg, unsigned long base, unsigned long size) } if (reg >= max) { - up(&main_lock); + up (&main_lock); printk ("mtrr: register: %d too big\n", reg); return -EINVAL; } if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) { - if ((reg == 3) && arr3_protected) + if ( (reg == 3) && arr3_protected ) { - up(&main_lock); + up (&main_lock); printk ("mtrr: ARR3 cannot be changed\n"); return -EINVAL; } @@ -1270,23 +1300,23 @@ int mtrr_del (int reg, unsigned long base, unsigned long size) (*get_mtrr) (reg, &lbase, &lsize, <ype); if (lsize < 1) { - up(&main_lock); + up (&main_lock); printk ("mtrr: MTRR %d not used\n", reg); return -EINVAL; } if (usage_table[reg] < 1) { - up(&main_lock); + up (&main_lock); printk ("mtrr: reg: %d has count=0\n", reg); return -EINVAL; } if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); compute_ascii (); - up(&main_lock); + up (&main_lock); return reg; } /* End Function mtrr_del */ -#ifdef CONFIG_PROC_FS +#ifdef USERSPACE_INTERFACE static int mtrr_file_add (unsigned long base, unsigned long size, unsigned int type, char increment, struct file *file) @@ -1469,18 +1499,25 @@ static int mtrr_close (struct inode *ino, struct file *file) static struct file_operations mtrr_fops = { - read: mtrr_read, - write: mtrr_write, - ioctl: mtrr_ioctl, - release: mtrr_close, + read: mtrr_read, + write: mtrr_write, + ioctl: mtrr_ioctl, + release: mtrr_close, }; -static struct inode_operations proc_mtrr_inode_operations = { - &mtrr_fops, /* default property file-ops */ +# ifdef CONFIG_PROC_FS + +static struct inode_operations proc_mtrr_inode_operations = +{ + &mtrr_fops, /* default property file-ops */ }; static struct proc_dir_entry *proc_root_mtrr; +# endif /* CONFIG_PROC_FS */ + +static devfs_handle_t devfs_handle = NULL; + static void compute_ascii (void) { char factor; @@ -1515,25 +1552,30 @@ static void compute_ascii (void) ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); } } + devfs_set_file_size (devfs_handle, ascii_buf_bytes); +# ifdef CONFIG_PROC_FS proc_root_mtrr->size = ascii_buf_bytes; +# endif /* CONFIG_PROC_FS */ } /* End Function compute_ascii */ -#endif /* CONFIG_PROC_FS */ +#endif /* USERSPACE_INTERFACE */ EXPORT_SYMBOL(mtrr_add); EXPORT_SYMBOL(mtrr_del); #ifdef __SMP__ -typedef struct { - unsigned long base; - unsigned long size; - mtrr_type type; +typedef struct +{ + unsigned long base; + unsigned long size; + mtrr_type type; } arr_state_t; -arr_state_t arr_state[8] __initdata = { - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} +arr_state_t arr_state[8] __initdata = +{ + {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, + {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} }; unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; @@ -1591,31 +1633,35 @@ static void __init cyrix_arr_init(void) ccr[5] = getCx86 (CX86_CCR5); ccr[6] = getCx86 (CX86_CCR6); - if (ccr[3] & 1) { - ccrc[3] = 1; - arr3_protected = 1; - } else { - /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and - * access to SMM memory through ARR3 (bit 7). - */ - if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } - if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } - if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } - arr3_protected = 0; - if (ccr[6] & 0x02) { - ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */ - setCx86 (CX86_CCR6, ccr[6]); - } - /* Disable ARR3. This is safe now that we disabled SMM. */ - /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ + if (ccr[3] & 1) + { + ccrc[3] = 1; + arr3_protected = 1; + } + else + { + /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and + * access to SMM memory through ARR3 (bit 7). + */ + if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } + if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } + if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } + arr3_protected = 0; + if (ccr[6] & 0x02) { + ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */ + setCx86 (CX86_CCR6, ccr[6]); + } + /* Disable ARR3. This is safe now that we disabled SMM. */ + /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ } /* If we changed CCR1 in memory, change it in the processor, too. */ if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]); /* Enable ARR usage by the processor */ - if (!(ccr[5] & 0x20)) { - ccr[5] |= 0x20; ccrc[5] = 1; - setCx86 (CX86_CCR5, ccr[5]); + if (!(ccr[5] & 0x20)) + { + ccr[5] |= 0x20; ccrc[5] = 1; + setCx86 (CX86_CCR5, ccr[5]); } #ifdef __SMP__ @@ -1667,11 +1713,14 @@ static void __init mtrr_setup(void) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ - get_mtrr = amd_get_mtrr; - set_mtrr_up = amd_set_mtrr_up; - break; - } /* else fall through */ + if (boot_cpu_data.x86 < 6) + { + /* pre-Athlon CPUs */ + get_mtrr = amd_get_mtrr; + set_mtrr_up = amd_set_mtrr_up; + break; + } + /* Else fall through */ case X86_VENDOR_INTEL: get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; @@ -1700,7 +1749,7 @@ void __init mtrr_init_boot_cpu(void) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ + if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */ case X86_VENDOR_INTEL: get_mtrr_state (&smp_mtrr_state); break; @@ -1738,7 +1787,7 @@ void __init mtrr_init_secondary_cpu(void) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - /* Just for robustness: pre-Athlon CPUs cannot do SMP. */ + /* Just for robustness: pre-Athlon CPUs cannot do SMP */ if (boot_cpu_data.x86 < 6) break; case X86_VENDOR_INTEL: intel_mtrr_init_secondary_cpu (); @@ -1762,17 +1811,17 @@ void __init mtrr_init_secondary_cpu(void) int __init mtrr_init(void) { if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; -# ifdef __SMP__ +#ifdef __SMP__ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ + if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */ case X86_VENDOR_INTEL: finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask); break; } -# else /* __SMP__ */ +#else /* __SMP__ */ mtrr_setup (); switch (boot_cpu_data.x86_vendor) { @@ -1783,12 +1832,17 @@ int __init mtrr_init(void) centaur_mcr_init (); break; } -# endif /* !__SMP__ */ +#endif /* !__SMP__ */ -# ifdef CONFIG_PROC_FS - proc_root_mtrr = create_proc_entry("mtrr", S_IWUSR|S_IRUGO, &proc_root); +#ifdef CONFIG_PROC_FS + proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); proc_root_mtrr->ops = &proc_mtrr_inode_operations; -#endif +#endif +#ifdev CONFIG_DEVFS_FS + devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0, + S_IFREG | S_IRUGO | S_IWUSR, 0, 0, + &mtrr_fops, NULL); +#endif init_table (); return 0; } /* End Function mtrr_init */ diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c index 18b203228..4bd1486fe 100644 --- a/arch/i386/kernel/pci-dma.c +++ b/arch/i386/kernel/pci-dma.c @@ -13,20 +13,6 @@ #include <linux/pci.h> #include <asm/io.h> -/* Pure 2^n version of get_order */ -extern __inline__ int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { @@ -35,7 +21,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, __get_order(size)); + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); @@ -47,5 +33,5 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, __get_order(size)); + free_pages((unsigned long)vaddr, get_order(size)); } diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c index ee2edca1e..6dd0a4306 100644 --- a/arch/i386/kernel/pci-i386.c +++ b/arch/i386/kernel/pci-i386.c @@ -132,7 +132,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) /* We need to avoid collisions with `mirrored' VGA ports and other strange ISA hardware, so we always want the addresses kilobyte aligned. */ - if (size >= 0x100) { + if (size > 0x100) { printk(KERN_ERR "PCI: I/O Region %s/%d too large" " (%ld bytes)\n", dev->slot_name, dev->resource - res, size); diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index 590e01fd5..d5b2b0062 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -883,6 +883,18 @@ static void __init pci_fixup_i450nx(struct pci_dev *d) } } +static void __init pci_fixup_i450gx(struct pci_dev *d) +{ + /* + * i450GX and i450KX -- Find and scan all secondary buses. + * (called separately for each PCI bridge found) + */ + u8 busno; + pci_read_config_byte(d, 0x4a, &busno); + printk("PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno); + pci_scan_bus(busno, pci_root_ops, NULL); +} + static void __init pci_fixup_rcc(struct pci_dev *d) { /* @@ -954,6 +966,7 @@ static void __init pci_fixup_ide_trash(struct pci_dev *d) struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_HE, pci_fixup_rcc }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_LE, pci_fixup_rcc }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq }, @@ -1036,6 +1049,18 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt) * table, but unfortunately we have to know the interrupt router chip. */ +/* + * Never use: 0, 1, 2 (timer, keyboard, and cascade) + * Avoid using: 13, 14 and 15 (FP error and IDE). + * Penalize: 3, 4, 7, 12 (known ISA uses: serial, parallel and mouse) + */ +static unsigned int pcibios_irq_mask = 0xfff8; + +static unsigned pcibios_irq_penalty[16] = { + 10000, 10000, 10000, 100, 100, 0, 0, 100, + 0, 0, 0, 0, 100, 1000, 1000, 1000 +}; + static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign) { struct irq_info *q; @@ -1043,6 +1068,7 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r int i, pirq, newirq; u32 rtrid, mask; u8 x; + char *msg = NULL; pin--; DBG("IRQ for %s(%d)", dev->slot_name, pin); @@ -1066,10 +1092,15 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r return NULL; } DBG(" -> PIRQ %02x, mask %04x", pirq, mask); - if (!assign || (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) - newirq = 0; - else for(newirq = 13; newirq && !(mask & (1 << newirq)); newirq--) - ; + newirq = 0; + if (assign && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { + for (i = 0; i < 16; i++) { + if (!(mask & pcibios_irq_mask & (1 << i))) + continue; + if (pcibios_irq_penalty[i] < pcibios_irq_penalty[newirq]) + newirq = i; + } + } if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) { DBG(" -> router not found\n"); return NULL; @@ -1094,27 +1125,30 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r pci_read_config_byte(router, pirq, &x); if (x < 16) { DBG(" -> [PIIX] %02x\n", x); - dev->irq = x; - return "PIIX"; + newirq = x; + msg = "PIIX"; } else if (newirq) { DBG(" -> [PIIX] set to %02x\n", newirq); pci_write_config_byte(router, pirq, newirq); - dev->irq = newirq; - return "PIIX-NEW"; - } - DBG(" -> [PIIX] sink\n"); - return NULL; + msg = "PIIX-NEW"; + } else + DBG(" -> [PIIX] sink\n"); + break; case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533): default: DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device); if (newirq && mask == (1 << newirq)) { /* Only one IRQ available -> use it */ - dev->irq = newirq; - return "guess"; + msg = "guess"; } - return NULL; } #undef ID + + if (msg) { + dev->irq = newirq; + pcibios_irq_penalty[newirq]++; + } + return msg; } static void __init pcibios_fixup_irqs(void) @@ -1134,6 +1168,18 @@ static void __init pcibios_fixup_irqs(void) pcibios_irq_peer_trick(rtable); pci_for_each_dev(dev) { + /* + * If the BIOS has set an out of range IRQ number, just ignore it. + * Also keep track of which IRQ's are already in use. + */ + if (dev->irq >= 16) { + DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq); + dev->irq = 0; + } + pcibios_irq_penalty[dev->irq]++; + } + + pci_for_each_dev(dev) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #if defined(CONFIG_X86_IO_APIC) /* @@ -1171,10 +1217,8 @@ static void __init pcibios_fixup_irqs(void) } #endif /* - * Fix out-of-range IRQ numbers and missing IRQs. + * Still no IRQ? Try to assign one... */ - if (dev->irq >= NR_IRQS) - dev->irq = 0; if (pin && !dev->irq && pirq_table) { char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 0); if (msg) @@ -1280,6 +1324,9 @@ char * __init pcibios_setup(char *str) } else if (!strcmp(str, "rom")) { pci_probe |= PCI_ASSIGN_ROMS; return NULL; + } else if (!strncmp(str, "irqmask=", 8)) { + pcibios_irq_mask = simple_strtol(str+8, NULL, 0); + return NULL; } return str; } diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index c38e383e7..0f61ca543 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -48,16 +48,6 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); int hlt_counter=0; -void disable_hlt(void) -{ - hlt_counter++; -} - -void enable_hlt(void) -{ - hlt_counter--; -} - /* * Powermanagement idle function, if any.. */ @@ -68,6 +58,16 @@ void (*pm_idle)(void) = NULL; */ void (*pm_power_off)(void) = NULL; +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + /* * We use this if we don't have any better * idle routine.. @@ -293,7 +293,7 @@ void machine_real_restart(unsigned char *code, int length) void machine_restart(char * __unused) { -#if __SMP__ +#if CONFIG_SMP /* * Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index e72f95160..cd2a3d8af 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1515,7 +1515,7 @@ unsigned long cpu_initialized = 0; * and IDT. We reload them nevertheless, this function acts as a * 'CPU state barrier', nothing should get across. */ -void cpu_init (void) +void __init cpu_init (void) { int nr = smp_processor_id(); struct tss_struct * t = &init_tss[nr]; diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 0b585513f..12f193c71 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -103,7 +103,7 @@ /* The 'big kernel lock' */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; -struct tlb_state cpu_tlbstate[NR_CPUS]; +struct tlb_state cpu_tlbstate[NR_CPUS] = {[0 ... NR_CPUS-1] = { &init_mm, 0 }}; /* * the following functions deal with sending IPIs between CPUs. @@ -347,12 +347,7 @@ asmlinkage void smp_invalidate_interrupt (void) __flush_tlb_one(flush_va); } else leave_mm(cpu); - } else { - extern void show_stack (void *); - printk("hm #1: %p, %p.\n", flush_mm, cpu_tlbstate[cpu].active_mm); - show_stack(NULL); } - __flush_tlb(); ack_APIC_irq(); clear_bit(cpu, &flush_cpumask); } @@ -382,7 +377,7 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, * Temporarily this turns IRQs off, so that lockups are * detected by the NMI watchdog. */ - spin_lock_irq(&tlbstate_lock); + spin_lock(&tlbstate_lock); flush_mm = mm; flush_va = va; @@ -398,7 +393,7 @@ static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, flush_mm = NULL; flush_va = 0; - spin_unlock_irq(&tlbstate_lock); + spin_unlock(&tlbstate_lock); } void flush_tlb_current_task(void) diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 4ef25674f..c3991b056 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -307,27 +307,30 @@ static void __init pagetable_init(void) pmd_t *pmd; pte_t *pte; int i, j, k; - unsigned long vaddr; - unsigned long end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); + unsigned long vaddr, end; - pgd_base = swapper_pg_dir; + end = (unsigned long)__va(max_low_pfn*PAGE_SIZE) - 1; - vaddr = PAGE_OFFSET; - i = __pgd_offset(vaddr); + i = __pgd_offset(PAGE_OFFSET); + pgd_base = swapper_pg_dir; pgd = pgd_base + i; - for (; (i < PTRS_PER_PGD) && (vaddr <= end); pgd++, i++) { + for (; i < PTRS_PER_PGD; pgd++, i++) { vaddr = i*PGDIR_SIZE; + if (vaddr >= end) + break; #if CONFIG_X86_PAE - pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); #else pmd = (pmd_t *)pgd; #endif if (pmd != pmd_offset(pgd, 0)) BUG(); - for (j = 0; (j < PTRS_PER_PMD) && (vaddr <= end); pmd++, j++) { + for (j = 0; j < PTRS_PER_PMD; pmd++, j++) { vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (vaddr >= end) + break; if (cpu_has_pse) { unsigned long __pe; @@ -349,10 +352,10 @@ static void __init pagetable_init(void) if (pte != pte_offset(pmd, 0)) BUG(); - for (k = 0; - (k < PTRS_PER_PTE) && (vaddr <= end); - pte++, k++) { + for (k = 0; k < PTRS_PER_PTE; pte++, k++) { vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + if (vaddr >= end) + break; *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL); } } diff --git a/arch/ia64/config.in b/arch/ia64/config.in index d006c1d05..2d2388590 100644 --- a/arch/ia64/config.in +++ b/arch/ia64/config.in @@ -3,6 +3,8 @@ mainmenu_name "Kernel configuration of Linux for IA-64 machines" mainmenu_option next_comment comment 'General setup' +define_bool CONFIG_IA64 y + choice 'IA-64 system type' \ "Generic CONFIG_IA64_GENERIC \ HP-simulator CONFIG_IA64_HP_SIM \ diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 1342e64f0..82ba58129 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -144,7 +144,7 @@ ia32_syscall_table: data8 sys32_settimeofday data8 sys_getgroups /* 80 */ data8 sys_setgroups - data8 sys_ni_syscall + data8 old_select data8 sys_symlink data8 sys_ni_syscall data8 sys_readlink /* 85 */ diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index ed443ee66..2c2c53741 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -342,7 +342,16 @@ ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, } asmlinkage int -sys32_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack) +sys32_sigreturn( +int arg0, +int arg1, +int arg2, +int arg3, +int arg4, +int arg5, +int arg6, +int arg7, +unsigned long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8); @@ -375,7 +384,16 @@ badframe: } asmlinkage int -sys32_rt_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack) +sys32_rt_sigreturn( +int arg0, +int arg1, +int arg2, +int arg3, +int arg4, +int arg5, +int arg6, +int arg7, +unsigned long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4); diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 7b4c4995e..d61f1cfe5 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -240,18 +240,29 @@ do_mmap_fake(struct file *file, unsigned long addr, unsigned long len, return -EINVAL; if (prot & PROT_WRITE) prot |= PROT_EXEC; +#ifdef DDD +#else // DDD + prot |= PROT_WRITE; +#endif // DDD front = NULL; back = NULL; if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { front = kmalloc(addr - baddr, GFP_KERNEL); memcpy(front, (void *)baddr, addr - baddr); } - if ((addr + len) & ~PAGE_MASK && get_user(c, (char *)(addr + len)) == 0) { +#ifndef DDD + if (addr) +#endif + if (((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); memcpy(back, addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } if ((r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0)) < 0) return(r); +#ifndef DDD + if (addr == 0) + addr = r; +#endif // DDD if (back) { memcpy(addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); kfree(back); @@ -315,7 +326,11 @@ sys32_mmap(struct mmap_arg_struct *arg) } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +#ifdef DDD if ((a.flags & MAP_FIXED) && ((a.addr & ~PAGE_MASK) || (a.offset & ~PAGE_MASK))) { +#else // DDD + if (1) { +#endif // DDD unlock_kernel(); up(¤t->mm->mmap_sem); error = do_mmap_fake(file, a.addr, a.len, a.prot, a.flags, a.offset); @@ -665,7 +680,7 @@ struct dirent32 { }; static void -xlate_dirent(void *dirent, long n) +xlate_dirent(void *dirent64, void *dirent32, long n) { long off; struct dirent *dirp; @@ -673,9 +688,9 @@ xlate_dirent(void *dirent, long n) off = 0; while (off < n) { - dirp = (struct dirent *)(dirent + off); + dirp = (struct dirent *)(dirent64 + off); + dirp32 = (struct dirent32 *)(dirent32 + off); off += dirp->d_reclen; - dirp32 = (struct dirent32 *)dirp; dirp32->d_ino = dirp->d_ino; dirp32->d_off = (unsigned int)dirp->d_off; dirp32->d_reclen = dirp->d_reclen; @@ -685,26 +700,27 @@ xlate_dirent(void *dirent, long n) } asmlinkage long -sys32_getdents(unsigned int fd, void * dirent, unsigned int count) +sys32_getdents(unsigned int fd, void * dirent32, unsigned int count) { long n; + void *dirent64; - if ((n = sys_getdents(fd, dirent, count)) < 0) + dirent64 = (unsigned long)(dirent32 + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + if ((n = sys_getdents(fd, dirent64, count - (dirent64 - dirent32))) < 0) return(n); - xlate_dirent(dirent, n); + xlate_dirent(dirent64, dirent32, n); return(n); } asmlinkage int -sys32_readdir(unsigned int fd, void * dirent, unsigned int count) +sys32_readdir(unsigned int fd, void * dirent32, unsigned int count) { int n; - struct dirent *dirp; + struct dirent dirent64; - if ((n = old_readdir(fd, dirent, count)) < 0) + if ((n = old_readdir(fd, &dirent64, count)) < 0) return(n); - dirp = (struct dirent *)dirent; - xlate_dirent(dirent, dirp->d_reclen); + xlate_dirent(&dirent64, dirent32, dirent64.d_reclen); return(n); } @@ -809,6 +825,23 @@ out_nofds: return ret; } +struct sel_arg_struct { + unsigned int n; + unsigned int inp; + unsigned int outp; + unsigned int exp; + unsigned int tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + return sys32_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + struct rusage32 { struct timeval32 ru_utime; struct timeval32 ru_stime; diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index dd7de2ab0..6e0d09ea7 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -15,7 +15,6 @@ * * Implemented EFI runtime services and virtual mode calls. --davidm */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> @@ -166,14 +165,12 @@ efi_memmap_walk (efi_freemem_callback_t callback, void *arg) case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: -#ifndef CONFIG_IA64_VIRTUAL_MEM_MAP if (md->phys_addr > 1024*1024*1024UL) { printk("Warning: ignoring %luMB of memory above 1GB!\n", md->num_pages >> 8); md->type = EFI_UNUSABLE_MEMORY; continue; } -#endif curr.start = PAGE_OFFSET + md->phys_addr; curr.end = curr.start + (md->num_pages << 12); diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 87e77c677..47b972cb4 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -496,18 +496,27 @@ ia64_ret_from_syscall: (p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure ia64_leave_kernel: - // check & deliver software interrupts (bottom half handlers): + // check & deliver software interrupts: - movl r2=bh_active // sheesh, why aren't these two in - movl r3=bh_mask // a struct?? +#ifdef CONFIG_SMP + adds r2=IA64_TASK_PROCESSOR_OFFSET,r13 + movl r3=softirq_state ;; - ld8 r2=[r2] - ld8 r3=[r3] + ld4 r2=[r2] + ;; + shladd r3=r2,3,r3 +#else + movl r3=softirq_state +#endif + ;; + ld8 r2=[r3] // r3 is guaranteed to be 8-byte aligned! + ;; + shr r3=r2,32 ;; and r2=r2,r3 ;; - cmp.ne p6,p7=r2,r0 // any soft interrupts ready for delivery? -(p6) br.call.dpnt.few rp=invoke_do_bottom_half + cmp4.ne p6,p7=r2,r0 +(p6) br.call.spnt.many rp=invoke_do_softirq 1: (pKern) br.cond.dpnt.many restore_all // yup -> skip check for rescheduling & signal delivery @@ -751,20 +760,20 @@ invoke_schedule_tail: #endif /* CONFIG_SMP */ /* - * Invoke do_bottom_half() while preserving in0-in7, which may be needed + * Invoke do_softirq() while preserving in0-in7, which may be needed * in case a system call gets restarted. */ - .proc invoke_do_bottom_half -invoke_do_bottom_half: + .proc invoke_do_softirq +invoke_do_softirq: alloc loc0=ar.pfs,8,2,0,0 mov loc1=rp ;; - br.call.sptk.few rp=do_bottom_half + br.call.sptk.few rp=do_softirq .ret9: mov ar.pfs=loc0 mov rp=loc1 br.ret.sptk.many rp - .endp invoke_do_bottom_half + .endp invoke_do_softirq /* * Invoke schedule() while preserving in0-in7, which may be needed diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S index 24dc10ee4..65de8e589 100644 --- a/arch/ia64/kernel/gate.S +++ b/arch/ia64/kernel/gate.S @@ -132,6 +132,7 @@ back_from_setup_rbs: ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0 cmp.ne p8,p0=r14,r15 // do we need to restore the rbs? (p8) br.cond.spnt.few restore_rbs // yup -> (clobbers r14 and r16) + ;; back_from_restore_rbs: { and r9=0x7f,r8 // r9 <- CFM0.sof diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 50d965e02..35a52628a 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -133,6 +133,7 @@ alive_msg: #endif /* CONFIG_IA64_EARLY_PRINTK */ alloc r2=ar.pfs,8,0,2,0 + ;; #ifdef CONFIG_SMP (isAP) br.call.sptk.few rp=smp_callin .ret1: @@ -174,7 +175,7 @@ ia64_save_debug_regs: st8.nta [in0]=r16,8 st8.nta [r19]=r17,8 br.cloop.sptk.few 1b - + ;; mov ar.lc=r20 // restore ar.lc br.ret.sptk.few b0 .endp ia64_save_debug_regs @@ -197,7 +198,7 @@ ia64_load_debug_regs: mov dbr[r18]=r16 mov ibr[r18]=r17 br.cloop.sptk.few 1b - + ;; mov ar.lc=r20 // restore ar.lc br.ret.sptk.few b0 .endp ia64_load_debug_regs diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 01c201137..5efe50164 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -128,6 +128,18 @@ get_irq_list (char *buf) return p - buf; } +int usbfix; + +static int __init +usbfix_option (char *str) +{ + printk("irq: enabling USB workaround\n"); + usbfix = 1; + return 1; +} + +__setup("usbfix", usbfix_option); + /* * That's where the IVT branches when we get an external * interrupt. This branches to the correct hardware IRQ handler via @@ -146,7 +158,8 @@ ia64_handle_irq (unsigned long irq, struct pt_regs *regs) unsigned long eoi_ptr; # ifdef CONFIG_USB - disable_usb(); + if (usbfix) + disable_usb(); # endif /* * Stop IPIs by getting the ivr_read_lock @@ -170,7 +183,8 @@ ia64_handle_irq (unsigned long irq, struct pt_regs *regs) spin_unlock(&ivr_read_lock); # ifdef CONFIG_USB - reenable_usb(); + if (usbfix) + reenable_usb(); # endif # ifndef CONFIG_SMP diff --git a/arch/ia64/kernel/irq_lock.c b/arch/ia64/kernel/irq_lock.c index 9c512dd4e..4a2ead673 100644 --- a/arch/ia64/kernel/irq_lock.c +++ b/arch/ia64/kernel/irq_lock.c @@ -26,7 +26,7 @@ int global_irq_holder = NO_PROC_ID; spinlock_t global_irq_lock; atomic_t global_irq_count; atomic_t global_bh_count; -atomic_t global_bh_lock; +spinlock_t global_bh_lock; #define INIT_STUCK (1<<26) diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index f86f45537..0bc110510 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c @@ -17,21 +17,6 @@ #include <asm/io.h> -/* Pure 2^n version of get_order */ -extern __inline__ unsigned long -get_order (unsigned long size) -{ - unsigned long order = ia64_fls(size); - - printk ("get_order: size=%lu, order=%lu\n", size, order); - - if (order > PAGE_SHIFT) - order -= PAGE_SHIFT; - else - order = 0; - return order; -} - void * pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { diff --git a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c index 3bceeed8e..4acc7f041 100644 --- a/arch/ia64/kernel/pci.c +++ b/arch/ia64/kernel/pci.c @@ -226,14 +226,3 @@ void pcibios_align_resource (void *data, struct resource *res, unsigned long size) { } - -#if 0 /*def CONFIG_PROC_FS*/ -/* - * This is an ugly hack to get a (weak) unresolved reference to something that is - * in drivers/pci/proc.c. Without this, the file does not get linked in at all - * (I suspect the reason this isn't needed on Linux/x86 is that most people compile - * with module support, in which case the EXPORT_SYMBOL() stuff will ensure the - * code gets linked in. Sigh... --davidm 99/12/20. - */ -asm ("data8 proc_bus_pci_add"); -#endif diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 48a3d68b4..ed5d594a6 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -57,7 +57,7 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map = 1; #endif -volatile int cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ +volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> SAPIC ID */ int smp_num_cpus = 1; int bootstrap_processor = -1; /* SAPIC ID of BSP */ @@ -586,7 +586,7 @@ smp_boot_one_cpu(int cpuid, int cpunum) alive: /* Remember the AP data */ - cpu_number_map[cpuid] = cpunum; + __cpu_number_map[cpuid] = cpunum; #ifdef CONFIG_KDB cpu_online_map |= (1<<cpunum); printk ("DEBUGGER: cpu_online_map = 0x%08x\n", cpu_online_map); @@ -612,12 +612,12 @@ smp_boot_cpus(void) extern int acpi_apic_map[32]; /* Take care of some initial bookkeeping. */ - memset(&cpu_number_map, -1, sizeof(cpu_number_map)); + memset(&__cpu_number_map, -1, sizeof(__cpu_number_map)); memset(&__cpu_logical_map, -1, sizeof(__cpu_logical_map)); memset(&ipi_op, 0, sizeof(ipi_op)); /* Setup BSP mappings */ - cpu_number_map[bootstrap_processor] = 0; + __cpu_number_map[bootstrap_processor] = 0; __cpu_logical_map[0] = bootstrap_processor; current->processor = bootstrap_processor; diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 18a498a09..f06d3bea8 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -2,8 +2,8 @@ * This file contains various system calls that have different calling * conventions on different platforms. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> #include <linux/errno.h> diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile index 8a9581747..88a4aadd4 100644 --- a/arch/ia64/lib/Makefile +++ b/arch/ia64/lib/Makefile @@ -3,7 +3,7 @@ # .S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@ + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@ OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o \ diff --git a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c index 85b15aae1..f1b298e21 100644 --- a/arch/ia64/tools/print_offsets.c +++ b/arch/ia64/tools/print_offsets.c @@ -47,6 +47,7 @@ tab[] = { "IA64_TASK_FLAGS_OFFSET", offsetof (struct task_struct, flags) }, { "IA64_TASK_SIGPENDING_OFFSET", offsetof (struct task_struct, sigpending) }, { "IA64_TASK_NEED_RESCHED_OFFSET", offsetof (struct task_struct, need_resched) }, + { "IA64_TASK_PROCESSOR_OFFSET", offsetof (struct task_struct, processor) }, { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, diff --git a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c index bf82e67ea..86bd24c73 100644 --- a/arch/m68k/atari/joystick.c +++ b/arch/m68k/atari/joystick.c @@ -12,6 +12,7 @@ #include <linux/major.h> #include <linux/poll.h> #include <linux/init.h> +#include <linux/devfs_fs_kernel.h> #include <asm/atarikb.h> #include <asm/atari_joystick.h> @@ -132,8 +133,11 @@ int __init atari_joystick_init(void) init_waitqueue_head(&joystick[0].wait); init_waitqueue_head(&joystick[1].wait); - if (register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops)) + if (devfs_register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops)) printk("unable to get major %d for joystick devices\n", MAJOR_NR); + devfs_register_series (NULL, "joysticks/digital%u", 2, DEVFS_FL_DEFAULT, + MAJOR_NR, 128, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + &atari_joystick_fops, NULL); return 0; } diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index 77053421e..7406a8d02 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -1168,7 +1168,7 @@ static void do_stram_request( void ) { unsigned long start, len; - while( CURRENT ) { + while( !QUEUE_EMPTY ) { if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) panic("stram: request list destroyed"); if (CURRENT->bh) { diff --git a/arch/m68k/config.in b/arch/m68k/config.in index ce8260504..5b12f470e 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -161,10 +161,17 @@ if [ "$CONFIG_SCSI" != "n" ]; then comment 'SCSI support type (disk, tape, CD-ROM)' dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + fi dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 + fi dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 fi dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI @@ -273,9 +280,13 @@ if [ "$CONFIG_NET" = "y" ]; then tristate ' Apollo 3c505 support' CONFIG_APOLLO_ELPLUS fi if [ "$CONFIG_MAC" = "y" ]; then - bool ' Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT -# bool ' Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE - bool ' Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC + bool ' Macintosh NS 8390 based ethernet cards' CONFIG_MAC8390 + tristate ' Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)' CONFIG_MACSONIC + tristate ' Macintosh SMC 9194 based ethernet cards' CONFIG_SMC9194 + tristate ' Macintosh CS89x0 based ethernet cards' CONFIG_MAC89x0 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)' CONFIG_MACMACE + fi fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then tristate ' MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET @@ -352,12 +363,6 @@ if [ "$CONFIG_ATARI" = "y" ]; then define_bool CONFIG_BUSMOUSE y fi fi -if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac ADB mouse support' CONFIG_ADBMOUSE - if [ "$CONFIG_ADBMOUSE" != "n" ]; then - define_bool CONFIG_BUSMOUSE y - fi -fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER tristate 'Atari SCC serial support' CONFIG_ATARI_SCC @@ -384,7 +389,20 @@ if [ "$CONFIG_PARPORT" = "n" ]; then fi fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac SCC serial support' CONFIG_MAC_SCC + tristate 'Macintosh serial support' CONFIG_MAC_SCC + bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB + if [ "$CONFIG_ADB" = "y" ]; then + bool ' Support for ADB keyboard' CONFIG_ADB_KEYBOARD + bool ' Support for ADB mouse' CONFIG_ADBMOUSE + bool ' Include Mac II ADB driver' CONFIG_ADB_MACII + bool ' Include Mac IIsi ADB driver' CONFIG_ADB_MACIISI + bool ' Include CUDA ADB driver' CONFIG_ADB_CUDA + bool ' Include IOP (IIfx/Quadra 9x0) ADB driver' CONFIG_ADB_IOP + bool ' Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU68K + fi + if [ "$CONFIG_ADBMOUSE" = "y" ]; then + define_bool CONFIG_BUSMOUSE y + fi fi if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then tristate 'HP DCA serial support' CONFIG_HPDCA diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 6d10ca35f..c51e43802 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -27,6 +27,8 @@ endif head.o: head.S m68k_defs.h +entry.o: entry.S m68k_defs.h + sun3-head.o: sun3-head.S m68k_defs.h m68k_defs.h: m68k_defs.c m68k_defs.head diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 021652201..5f08ef216 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -236,12 +236,12 @@ SYMBOL_NAME_LABEL(ret_from_interrupt) #endif /* check if we need to do software interrupts */ - movel SYMBOL_NAME(bh_active),%d0 - andl SYMBOL_NAME(bh_mask),%d0 + movel SYMBOL_NAME(softirq_state),%d0 + andl SYMBOL_NAME(softirq_state)+4,%d0 jeq SYMBOL_NAME(ret_from_exception) pea SYMBOL_NAME(ret_from_exception) - jra SYMBOL_NAME(do_bottom_half) + jra SYMBOL_NAME(do_softirq) /* Handler for uninitialized and spurious interrupts */ diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 790d153ab..6f8300422 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -18,7 +18,6 @@ #include <asm/checksum.h> #include <asm/hardirq.h> #include <asm/softirq.h> -#include <asm/m68kserial.h> asmlinkage long long __ashrdi3 (long long, int); asmlinkage long long __lshrdi3 (long long, int); diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile index 10613c0a4..f50cd262c 100644 --- a/arch/m68k/mac/Makefile +++ b/arch/m68k/mac/Makefile @@ -10,6 +10,6 @@ O_TARGET := mac.o OX_OBJS := mac_ksyms.o O_OBJS := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ - macboing.o debug.o misc.o + baboon.o macboing.o debug.o misc.o include $(TOPDIR)/Rules.make diff --git a/arch/m68k/mac/adb-bus.c b/arch/m68k/mac/adb-bus.c deleted file mode 100644 index 23e98c048..000000000 --- a/arch/m68k/mac/adb-bus.c +++ /dev/null @@ -1,2699 +0,0 @@ -/* - * MACII ADB keyboard handler. - * Copyright (c) 1997 Alan Cox - * - * Derived from code - * Copyright (C) 1996 Paul Mackerras. - * - * MSch (9/97) Partial rewrite of interrupt handler to MacII style - * ADB handshake, based on: - * - Guide to Mac Hardware - * - Guido Koerber's session with a logic analyzer - * - * MSch (1/98) Integrated start of IIsi driver by Robert Thompson - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/miscdevice.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/malloc.h> -#include <linux/mm.h> -#include "via6522.h" - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/adb.h> -#include <asm/system.h> -#include <asm/segment.h> -#include <asm/setup.h> -#include <asm/macintosh.h> -#include <asm/macints.h> - - -#define MACII /* For now - will be a switch */ - -/* Bits in B data register: all active low */ -#define TREQ 0x08 /* Transfer request (input) */ -#define TACK 0x10 /* Transfer acknowledge (output) */ -#define TIP 0x20 /* Transfer in progress (output) */ - -/* Bits in B data register: ADB transaction states MacII */ -#define ST_MASK 0x30 /* mask for selecting ADB state bits */ -/* ADB transaction states according to GMHW */ -#define ST_CMD 0x00 /* ADB state: command byte */ -#define ST_EVEN 0x10 /* ADB state: even data byte */ -#define ST_ODD 0x20 /* ADB state: odd data byte */ -#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ - -/* Bits in ACR */ -#define SR_CTRL 0x1c /* Shift register control bits */ -#ifdef USE_ORIG -#define SR_EXT 0x1c /* Shift on external clock */ -#else -#define SR_EXT 0x0c /* Shift on external clock */ -#endif -#define SR_OUT 0x10 /* Shift out if 1 */ - -/* Bits in IFR and IER */ -#define IER_SET 0x80 /* set bits in IER */ -#define IER_CLR 0 /* clear bits in IER */ -#define SR_INT 0x04 /* Shift register full/empty */ -#define SR_DATA 0x08 /* Shift register data */ -#define SR_CLOCK 0x10 /* Shift register clock */ - -/* JRT */ -#define ADB_DELAY 150 - -static struct adb_handler { - void (*handler)(unsigned char *, int, struct pt_regs *); -} adb_handler[16]; - -static enum adb_state { - idle, - sent_first_byte, - sending, - reading, - read_done, - awaiting_reply -} adb_state; - -static struct adb_request *current_req; -static struct adb_request *last_req; -static unsigned char cuda_rbuf[16]; -static unsigned char *reply_ptr; -static int reply_len; -static int reading_reply; -static int data_index; -static int first_byte; -static int prefix_len; - -static int status = ST_IDLE|TREQ; -static int last_status; - -static int driver_running = 0; - -/*static int adb_delay;*/ -int in_keybinit = 1; - -static void adb_start(void); -extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); -static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); - -static void adb_hw_setup_IIsi(void); -static void adb_hw_setup_cuda(void); - -/* - * debug level 10 required for ADB logging (should be && debug_adb, ideally) - */ - -extern int console_loglevel; - -/* - * Misc. defines for testing - should go to header :-( - */ - -#define ADBDEBUG_STATUS (1) -#define ADBDEBUG_STATE (2) -#define ADBDEBUG_READ (4) -#define ADBDEBUG_WRITE (8) -#define ADBDEBUG_START (16) -#define ADBDEBUG_RETRY (32) -#define ADBDEBUG_POLL (64) -#define ADBDEBUG_INT (128) -#define ADBDEBUG_PROT (256) -#define ADBDEBUG_SRQ (512) -#define ADBDEBUG_REQUEST (1024) -#define ADBDEBUG_INPUT (2048) -#define ADBDEBUG_DEVICE (4096) - -#define ADBDEBUG_IISI (8192) - - -/*#define DEBUG_ADB*/ - -#ifdef DEBUG_ADB -#define ADBDEBUG (ADBDEBUG_INPUT | ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST) -#else -#define ADBDEBUG (0) -#endif - -#define TRY_CUDA - -void adb_bus_init(void) -{ - unsigned long flags; - unsigned char c, i; - - save_flags(flags); - cli(); - - /* - * Setup ADB - */ - - switch(macintosh_config->adb_type) - { - - case MAC_ADB_II: - printk("adb: MacII style keyboard/mouse driver.\n"); - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); - /* - * Docs suggest TREQ should be output - that seems nuts - * BSD agrees here :-) - * Setup vPCR ?? - */ - -#ifdef USE_ORIG - /* Lower the bus signals (MacII is active low it seems ???) */ - via_write(via1, vBufB, via_read(via1, vBufB)&~TACK); -#else - /* Corresponding state: idle (clear state bits) */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - last_status = (via_read(via1, vBufB)&~ST_MASK); -#endif - /* Shift register on input */ - c=via_read(via1, vACR); - c&=~SR_CTRL; /* Clear shift register bits */ - c|=SR_EXT; /* Shift on external clock; out or in? */ - via_write(via1, vACR, c); - /* Wipe any pending data and int */ - via_read(via1, vSR); - - /* This is interrupts on enable SR for keyboard */ - via_write(via1, vIER, IER_SET|SR_INT); - /* This clears the interrupt bit */ - via_write(via1, vIFR, SR_INT); - - /* - * Ok we probably ;) have a ready to use adb bus. Its also - * hopefully idle (Im assuming the mac didnt leave a half - * complete transaction on booting us). - */ - - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_interrupt); - adb_state = idle; - break; - /* - * Unsupported; but later code doesn't notice !! - */ - case MAC_ADB_CUDA: - printk("adb: CUDA interface.\n"); -#if 0 - /* don't know what to set up here ... */ - adb_state = idle; - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); -#endif - adb_hw_setup_cuda(); - adb_state = idle; - request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, - "adb CUDA interrupt", adb_cuda_interrupt); - break; - case MAC_ADB_IISI: - printk("adb: Using IIsi hardware.\n"); - printk("\tDEBUG_JRT\n"); - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); - - /* - * MSch: I'm pretty sure the setup is mildly wrong - * for the IIsi. - */ - /* Initial state: idle (clear state bits) */ - via_write(via1, vBufB, (via_read(via1, vBufB) & ~(TIP|TACK)) ); - last_status = (via_read(via1, vBufB)&~ST_MASK); - /* Shift register on input */ - c=via_read(via1, vACR); - c&=~SR_CTRL; /* Clear shift register bits */ - c|=SR_EXT; /* Shift on external clock; out or in? */ - via_write(via1, vACR, c); - /* Wipe any pending data and int */ - via_read(via1, vSR); - - /* This is interrupts on enable SR for keyboard */ - via_write(via1, vIER, IER_SET|SR_INT); - /* This clears the interrupt bit */ - via_write(via1, vIFR, SR_INT); - - /* get those pesky clock ticks we missed while booting */ - for ( i = 0; i < 60; i++) { - udelay(ADB_DELAY); - adb_hw_setup_IIsi(); - udelay(ADB_DELAY); - if (via_read(via1, vBufB) & TREQ) - break; - } - if (i == 60) - printk("adb_IIsi: maybe bus jammed ??\n"); - - /* - * Ok we probably ;) have a ready to use adb bus. Its also - */ - request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_cuda_interrupt); - adb_state = idle; - break; - default: - printk("adb: Unknown hardware interface.\n"); - nosupp: - printk("adb: Interface unsupported.\n"); - restore_flags(flags); - return; - } - - /* - * XXX: interrupt only registered if supported HW !! - * -> unsupported HW will just time out on keyb_init! - */ -#if 0 - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_interrupt); -#endif -#ifdef DEBUG_ADB_INTS - request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, - "adb clock interrupt", adb_clock_interrupt); - request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK, - "adb data interrupt", adb_data_interrupt); -#endif - - printk("adb: init done.\n"); - restore_flags(flags); -} - -void adb_hw_setup_cuda(void) -{ - int x; - unsigned long flags; - - printk("CUDA: HW Setup:"); - - save_flags(flags); - cli(); - - if (console_loglevel == 10) - printk(" 1,"); - - /* Set the direction of the cuda signals, TIP+TACK are output TREQ is an input */ - via_write( via1, vDirB, via_read( via1, vDirB ) | TIP | TACK ); - via_write( via1, vDirB, via_read( via1, vDirB ) & ~TREQ ); - - if (console_loglevel == 10) - printk("2,"); - - /* Set the clock control. Set to shift data in by external clock CB1 */ - via_write( via1, vACR, ( via_read(via1, vACR ) | SR_EXT ) & ~SR_OUT ); - - if (console_loglevel == 10) - printk("3,"); - - /* Clear any possible Cuda interrupt */ - x = via_read( via1, vSR ); - - if (console_loglevel == 10) - printk("4,"); - - /* Terminate transaction and set idle state */ - via_write( via1, vBufB, via_read( via1, vBufB ) | TIP | TACK ); - - if (console_loglevel == 10) - printk("5,"); - - /* Delay 4 mS for ADB reset to complete */ - udelay(4000); - - if (console_loglevel == 10) - printk("6,"); - - /* Clear pending interrupts... */ - x = via_read( via1, vSR ); - - if (console_loglevel == 10) - printk("7,"); - /* Issue a sync transaction, TACK asserted while TIP negated */ - via_write( via1, vBufB, via_read( via1, vBufB ) & ~TACK ); - - if (console_loglevel == 10) - printk("8,"); - - /* Wait for the sync acknowledgement, Cuda to assert TREQ */ - while( ( via_read( via1, vBufB ) & TREQ ) != 0 ) - barrier(); - - if (console_loglevel == 10) - printk("9,"); - - /* Wait for the sync acknowledment interrupt */ - while( ( via_read( via1, vIFR ) & SR_INT ) == 0 ) - barrier(); - - if (console_loglevel == 10) - printk("10,"); - - /* Clear pending interrupts... */ - x = via_read( via1, vSR ); - - if (console_loglevel == 10) - printk("11,"); - - /* Terminate the sync cycle by negating TACK */ - via_write( via1, vBufB, via_read( via1, vBufB ) | TACK ); - - if (console_loglevel == 10) - printk("12,"); - - /* Wait for the sync termination acknowledgement, Cuda to negate TREQ */ - while( ( via_read( via1, vBufB ) & TREQ ) == 0 ) - barrier(); - - if (console_loglevel == 10) - printk("13,"); - - /* Wait for the sync termination acknowledment interrupt */ - while( ( via_read( via1, vIFR ) & SR_INT ) == 0 ) - barrier(); - - if (console_loglevel == 10) - printk("14,"); - - /* Terminate transaction and set idle state, TIP+TACK negate */ - via_write( via1, vBufB, via_read( via1, vBufB ) | TIP ); - - if (console_loglevel == 10) - printk("15 !"); - - /* Clear pending interrupts... */ - x = via_read( via1, vSR ); - - restore_flags(flags); - - printk("\nCUDA: HW Setup done!\n"); -} - -void adb_hw_setup_IIsi(void) -{ - int dummy; - long poll_timeout; - - printk("adb_IIsi: cleanup!\n"); - - /* ??? */ - udelay(ADB_DELAY); - - /* disable SR int. */ - via_write(via1, vIER, IER_CLR|SR_INT); - /* set SR to shift in */ - via_write(via1, vACR, via_read(via1, vACR ) & ~SR_OUT); - - /* this is required, especially on faster machines */ - udelay(ADB_DELAY); - - if (!(via_read(via1, vBufB) & TREQ)) { /* IRQ on */ - /* start frame */ - via_write(via1, vBufB,via_read(via1,vBufB) | TIP); - - while (1) { - /* poll for ADB interrupt and watch for timeout */ - /* if time out, keep going in hopes of not hanging the - * ADB chip - I think */ - poll_timeout = ADB_DELAY * 5; - while ( !(via_read(via1, vIFR) & SR_INT) - && (poll_timeout-- > 0) ) - dummy = via_read(via1, vBufB); - - dummy = via_read(via1, vSR); /* reset interrupt flag */ - - /* perhaps put in a check here that ignores all data - * after the first ADB_MAX_MSG_LENGTH bytes ??? */ - - /* end of frame reached ?? */ - if (via_read(via1, vBufB) & TREQ) - break; - - /* set ACK */ - via_write(via1,vBufB,via_read(via1, vBufB) | TACK); - /* delay */ - udelay(ADB_DELAY); - /* clear ACK */ - via_write(via1,vBufB,via_read(via1, vBufB) & ~TACK); - } - /* end frame */ - via_write(via1, vBufB,via_read(via1,vBufB) & ~TIP); - /* probably don't need to delay this long */ - udelay(ADB_DELAY); - } - /* re-enable SR int. */ - via_write(via1, vIER, IER_SET|SR_INT); -} - -#define WAIT_FOR(cond, what) \ - do { \ - for (x = 1000; !(cond); --x) { \ - if (x == 0) { \ - printk("Timeout waiting for " what); \ - return 0; \ - } \ - __delay(100*160); \ - } \ - } while (0) - -/* - * Construct and send an adb request - * This function is the main entry point into the ADB driver from - * kernel code; it takes the request data supplied and populates the - * adb_request structure. - * In order to keep this interface independent from any assumption about - * the underlying ADB hardware, we take requests in CUDA format here, - * the ADB packet 'prefixed' with a packet type code. - * Non-CUDA hardware is confused by this, so we strip the packet type - * here depending on hardware type ... - */ -int adb_request(struct adb_request *req, void (*done)(struct adb_request *), - int nbytes, ...) -{ - va_list list; - int i, start; - - va_start(list, nbytes); - - /* - * skip first byte if not CUDA - */ - if (macintosh_config->adb_type == MAC_ADB_II) { - start = va_arg(list, int); - nbytes--; - } - req->nbytes = nbytes; - req->done = done; -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("adb_request, data bytes: "); -#endif - for (i = 0; i < nbytes; ++i) { - req->data[i] = va_arg(list, int); -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("%x ", req->data[i]); -#endif - } -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk(" !\n"); -#endif - va_end(list); - /* - * XXX: This might be fatal if no reply is generated (i.e. Listen) ! - * Currently, the interrupt handler 'fakes' a reply on non-TALK - * commands for this reason. - * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA - * Macs, and some mechanism to remember the last issued TALK - * request for resending it repeatedly on timeout! - */ - req->reply_expected = 1; - return adb_send_request(req); -} - -/* - * Construct an adb request for later sending - * This function only populates the adb_request structure, without - * actually queueing it. - * Reason: Poll requests and Talk requests need to be handled in a way - * different from 'user' requests; no reply_expected is set and - * Poll requests need to be placed at the head of the request queue. - * Using adb_request results in implicit queueing at the tail of the - * request queue (duplicating the Poll) with reply_expected set. - * No adjustment of packet data is necessary, as this mechanisnm is not - * used by CUDA hardware (Autopoll used instead). - */ -int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *), - int nbytes, ...) -{ - va_list list; - int i; - - req->nbytes = nbytes; - req->done = done; - va_start(list, nbytes); -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("adb__build_request, data bytes: "); -#endif - /* - * skip first byte if not CUDA ? - */ - for (i = 0; i < nbytes; ++i) { - req->data[i] = va_arg(list, int); -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("%x ", req->data[i]); -#endif - } -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk(" !\n"); -#endif - va_end(list); - - req->reply_expected = 0; - return 0; -} - -/* - * Send an ADB poll (Talk, tagged on the front of the request queue) - */ -void adb_queue_poll(void) -{ - static int pod=0; - static int in_poll=0; - static struct adb_request r; - unsigned long flags; - - if(in_poll) - printk("Double poll!\n"); - - in_poll++; - pod++; - if(pod>7) /* 15 */ - pod=0; - -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("adb: Polling %d\n",pod); -#endif - - if (macintosh_config->adb_type == MAC_ADB_II) - /* XXX: that's a TALK, register 0, MacII version */ - adb_build_request(&r,NULL, 1, (pod<<4|0xC)); - else - /* CUDA etc. version */ - adb_build_request(&r,NULL, 2, 0, (pod<<4|0xC)); - - r.reply_expected=0; - r.done=NULL; - r.sent=0; - r.got_reply=0; - r.reply_len=0; - save_flags(flags); - cli(); - /* Poll inserted at head of queue ... */ - r.next=current_req; - current_req=&r; - restore_flags(flags); - adb_start(); - in_poll--; -} - -/* - * Send an ADB retransmit (Talk, appended to the request queue) - */ -void adb_retransmit(int device) -{ - static int in_retransmit=0; - static struct adb_request rt; - unsigned long flags; - - if(in_retransmit) - printk("Double retransmit!\n"); - - in_retransmit++; - -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("adb: Sending retransmit: %d\n", device); -#endif - - /* MacII version */ - adb_build_request(&rt,NULL, 1, (device<<4|0xC)); - - rt.reply_expected = 0; - rt.done = NULL; - rt.sent = 0; - rt.got_reply = 0; - rt.reply_len = 0; - rt.next = NULL; - - save_flags(flags); - cli(); - - /* Retransmit inserted at tail of queue ... */ - - if (current_req != NULL) - { - last_req->next = &rt; - last_req = &rt; - } - else - { - current_req = &rt; - last_req = &rt; - } - - /* always restart driver (send_retransmit used in place of adb_start!)*/ - - if (adb_state == idle) - adb_start(); - - restore_flags(flags); - in_retransmit--; -} - -/* - * Queue an ADB request; start ADB transfer if necessary - */ -int adb_send_request(struct adb_request *req) -{ - unsigned long flags; - - req->next = 0; - req->sent = 0; - req->got_reply = 0; - req->reply_len = 0; - save_flags(flags); - cli(); - - if (current_req != NULL) - { - last_req->next = req; - last_req = req; - } - else - { - current_req = req; - last_req = req; - if (adb_state == idle) - adb_start(); - } - - restore_flags(flags); - return 0; -} - -static int nclock, ndata; - -static int need_poll = 0; -static int command_byte = 0; -static int last_reply = 0; -static int last_active = 0; - -static struct adb_request *retry_req; - -/* - * Start sending ADB packet - */ -static void adb_start(void) -{ - unsigned long flags; - struct adb_request *req; - - /* - * We get here on three 'sane' conditions: - * 1) called from send_adb_request, if adb_state == idle - * 2) called from within adb_interrupt, if adb_state == idle - * (after receiving, or after sending a LISTEN) - * 3) called from within adb_interrupt, if adb_state == sending - * and no reply is expected (immediate next command). - * Maybe we get here on SRQ as well ?? - */ - - /* get the packet to send */ - req = current_req; - /* assert adb_state == idle */ - if (adb_state != idle) { - printk("ADB: adb_start called while driver busy (%p %x %x)!\n", - req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); - return; - } - if (req == 0) - return; - save_flags(flags); - cli(); - -#if (ADBDEBUG & ADBDEBUG_START) - if (console_loglevel == 10) - printk("adb_start: request %p ", req); -#endif - - nclock = 0; - ndata = 0; - - /* - * IRQ signaled ?? (means ADB controller wants to send, or might - * be end of packet if we were reading) - */ - if ((via_read(via1, vBufB) & TREQ) == 0) - { - switch(macintosh_config->adb_type) - { - /* - * FIXME - we need to restart this on a timer - * or a collision at boot hangs us. - * Never set adb_state to idle here, or adb_start - * won't be called again from send_request! - * (need to re-check other cases ...) - */ - case MAC_ADB_CUDA: - /* printk("device busy - fail\n"); */ - restore_flags(flags); - /* a byte is coming in from the CUDA */ - return; - case MAC_ADB_IISI: - printk("adb_start: device busy - fail\n"); - retry_req = req; - restore_flags(flags); - return; - case MAC_ADB_II: - /* - * if the interrupt handler set the need_poll - * flag, it's hopefully a SRQ poll or re-Talk - * so we try to send here anyway - */ - if (!need_poll) { - printk("device busy - retry %p state %d status %x!\n", - req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); - retry_req = req; - /* set ADB status here ? */ - restore_flags(flags); - return; - } else { -#if (ADBDEBUG & ADBDEBUG_START) - if (console_loglevel == 10) - printk("device busy - polling; state %d status %x!\n", - adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); -#endif - need_poll = 0; - break; - } - } - } - -#if 0 - /* - * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here! - * OTOH: setting ST_CMD in the interrupt routine would make the - * ADB contoller shift in before this routine starts shifting out ... - */ - if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE) - { -#if (ADBDEBUG & ADBDEBUG_STATE) - if (console_loglevel == 10) - printk("ADB bus not idle (%x), retry later!\n", - via_read(via1, vBufB)&(ST_MASK|TREQ)); -#endif - retry_req = req; - restore_flags(flags); - return; - } -#endif - - /* - * Another retry pending? (sanity check) - */ - if (retry_req) { -#if (ADBDEBUG & ADBDEBUG_RETRY) - if (console_loglevel == 10) - if (retry_req == req) - /* new requests are appended at tail of request queue */ - printk("adb_start: retry %p pending ! \n", req); - else - /* poll requests are added to the head of queue */ - printk("adb_start: retry %p pending, req %p (poll?) current! \n", - retry_req, req); -#endif - retry_req = NULL; - } - - /* - * Seems OK, go for it! - */ - switch(macintosh_config->adb_type) - { - case MAC_ADB_CUDA: - /* store command byte (first byte is 'type' byte) */ - command_byte = req->data[1]; - /* set the shift register to shift out and send a byte */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - via_write(via1, vSR, req->data[0]); - via_write(via1, vBufB, via_read(via1, vBufB)&~TIP); - break; - case MAC_ADB_IISI: - /* store command byte (first byte is 'type' byte) */ - command_byte = req->data[1]; - /* set ADB state to 'active' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* switch ACK off (in case it was left on) */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* set the shift register to shift out and send a byte */ - via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); - via_write(via1, vSR, req->data[0]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - break; - case MAC_ADB_II: - /* store command byte */ - command_byte = req->data[0]; - /* Output mode */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - /* Load data */ - via_write(via1, vSR, req->data[0]); -#ifdef USE_ORIG - /* Turn off TIP/TACK - this should tell the external logic to - start the external shift clock */ -/* via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/ - via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK)); -#else - /* set ADB state to 'command' */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD); -#endif - break; - } - adb_state = sent_first_byte; - data_index = 1; -#if (ADBDEBUG & ADBDEBUG_START) - if (console_loglevel == 10) - printk("sent first byte of %d: %x, (%x %x) ... ", - req->nbytes, req->data[0], adb_state, - (via_read(via1, vBufB) & (ST_MASK|TREQ)) ); -#endif - restore_flags(flags); -} - -/* - * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs) - */ -void adb_poll(void) -{ - unsigned char c; - unsigned long flags; - save_flags(flags); - cli(); - c=via_read(via1, vIFR); -#if (ADBDEBUG & ADBDEBUG_POLL) -#ifdef DEBUG_ADB_INTS - if (console_loglevel == 10) { - printk("adb_poll: IFR %x state %x cl %d dat %d ", - c, adb_state, nclock, ndata); - if (c & (SR_CLOCK|SR_DATA)) { - if (c & SR_CLOCK) - printk("adb clock event "); - if (c & SR_DATA) - printk("adb data event "); - } - } -#else - if (console_loglevel == 10) - printk("adb_poll: IFR %x state %x ", - c, adb_state); -#endif - if (console_loglevel == 10) - printk("\r"); -#endif - if (c & SR_INT) - { -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("adb_poll: adb interrupt event\n"); -#endif - adb_interrupt(0, 0, 0); - } - restore_flags(flags); -} - -/* - * Debugging gimmicks - */ -void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - nclock++; -} - -void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - ndata++; -} - -/* - * The notorious ADB interrupt handler - does all of the protocol handling, - * except for starting new send operations. Relies heavily on the ADB - * controller sending and receiving data, thereby generating SR interrupts - * for us. This means there has to be always activity on the ADB bus, otherwise - * the whole process dies and has to be re-kicked by sending TALK requests ... - * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type - * ADB the problem isn't solved yet (retransmit of the latest active TALK seems - * a good choice; either on timeout or on a timer interrupt). - * - * The basic ADB state machine was left unchanged from the original MacII code - * by Alan Cox, which was based on the CUDA driver for PowerMac. - * The syntax of the ADB status lines seems to be totally different on MacII, - * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for - * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start - * and end of a receive packet are signaled by asserting /IRQ on the interrupt - * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on - * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the - * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB - * protocol with a logic analyzer!!) - * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK - * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for - * receiving. No clue how timeouts are handled; SRQ seems to be sent as a - * separate packet. Quite a few changes have been made outside the handshake - * code, so I don't know if the CUDA code still behaves as before. - * - * Note: As of 21/10/97, the MacII ADB part works including timeout detection - * and retransmit (Talk to the last active device). Cleanup of code and - * testing of the CUDA functionality is required, though. - * Note2: As of 13/12/97, CUDA support is definitely broken ... - * Note3: As of 21/12/97, CUDA works on a P475. What was broken? The assumption - * that Q700 and Q800 use CUDA :-( - * - * 27/01/98: IIsi driver implemented (thanks to Robert Thompson for the - * initial bits). See adb_cuda_interrupts ... - * - * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG - * conditionals can be a start?) - */ -void adb_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - int x, adbdir; - unsigned long flags; - struct adb_request *req; - - last_status = status; - - /* prevent races due to SCSI enabling ints */ - save_flags(flags); - cli(); - - if (driver_running) { - restore_flags(flags); - return; - } - - driver_running = 1; - -#ifdef USE_ORIG - status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); -#else - if (macintosh_config->adb_type==MAC_ADB_CUDA) - status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); - else - /* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */ - status = (via_read(via1, vBufB) & (ST_MASK|TREQ)); -#endif - adbdir = (via_read(via1, vACR) & SR_OUT); -#if (ADBDEBUG & ADBDEBUG_INT) - if (console_loglevel == 10) - printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n", - adb_state, status, last_status, adbdir); -#endif - - switch (adb_state) - { - case idle: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - /* CUDA has sent us the first byte of data - unsolicited */ - if (status != TREQ) - printk("cuda: state=idle, status=%x\n", status); - x = via_read(via1, vSR); - via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - udelay(150); - /* set SR to IN (??? no byte received else) */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macIIsi : receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status == TREQ && !adbdir) - /* that's: not IRQ, idle, input -> weird */ - printk("adb_macII: idle, status=%x dir=%x\n", - status, adbdir); -#endif - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macII: receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - /* set ADB state = even for first data byte */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - } - adb_state = reading; - reply_ptr = cuda_rbuf; - reply_len = 0; - reading_reply = 0; - prefix_len = 0; - if (macintosh_config->adb_type==MAC_ADB_II) { - *reply_ptr++ = ADB_PACKET; - *reply_ptr++ = first_byte; - *reply_ptr++ = command_byte; /*first_byte;*/ - reply_len = 3; - prefix_len = 3; - } - break; - - case awaiting_reply: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - /* CUDA has sent us the first byte of data of a reply */ - if (status != TREQ) - printk("cuda: state=awaiting_reply, status=%x\n", status); - x = via_read(via1, vSR); - via_write(via1,vBufB, - via_read(via1, vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* set SR to IN */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macIIsi: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif -#if 0 - if( via_read(via1,vBufB) & TREQ) - ending = 1; - else - ending = 0; -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - /* handshake etc. for II ?? */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macII: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif - /* set ADB state = even for first data byte */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - } - adb_state = reading; - reply_ptr = current_req->reply; - reading_reply = 1; - reply_len = 0; - prefix_len = 0; - if (macintosh_config->adb_type==MAC_ADB_II) { - *reply_ptr++ = ADB_PACKET; - *reply_ptr++ = first_byte; - *reply_ptr++ = first_byte; /* should be command byte */ - reply_len = 3; - prefix_len = 3; - } - break; - - case sent_first_byte: -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" sending: %x (%x %x) ", - current_req->data[1], adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - if (status == TREQ + TIP + SR_OUT) - { - /* collision */ - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TIP|TACK); - adb_state = idle; - } - else - { - /* assert status == TIP + SR_OUT */ - if (status != TIP + SR_OUT) - printk("cuda: state=sent_first_byte status=%x\n", status); - via_write(via1,vSR,current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index = 2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - if ( !(via_read(via1, vBufB) & TREQ) ) - { - /* collision */ -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("adb_macIIsi: send collison, aborting!\n"); -#endif - /* set shift in */ - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state to 'idle' */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TIP|TACK)); - adb_state = idle; - } - else - { - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); -#endif - via_write(via1, vSR, current_req->data[1]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - data_index=2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - /* how to detect a collision here ?? */ - /* maybe we're already done (Talk, or Poll)? */ - if (data_index >= current_req->nbytes) - { - /* assert it's a Talk ?? */ - if ( (command_byte&0xc) != 0xc - && console_loglevel == 10 ) - printk("ADB: single byte command, no Talk: %x!\n", - command_byte); -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" -> end (%d of %d) (%x %x)!\n", - data_index, current_req->nbytes, adb_state, status); -#endif - current_req->sent = 1; - if (current_req->reply_expected) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("ADB: reply expected on poll!\n"); -#endif - adb_state = awaiting_reply; - reading_reply = 0; - } else { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("ADB: no reply for poll, not calling done()!\n"); -#endif - req = current_req; - current_req = req->next; -#if 0 /* XXX Not sure about that one ... probably better enabled */ - if (req->done) - (*req->done)(req); -#endif - adb_state = idle; - reading_reply = 0; - } - /* set to shift in */ - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - /* set ADB state idle - might get SRQ */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - break; - } -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT)) - printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n", - status, adbdir); -#endif - /* SR already set to shift out; send byte */ - via_write(via1, vSR, current_req->data[1]); - /* set state to ST_EVEN (first byte was: ST_CMD) */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - data_index=2; - adb_state = sending; - } - break; - - case sending: - req = current_req; - if (data_index >= req->nbytes) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" -> end (%d of %d) (%x %x)!\n", - data_index-1, req->nbytes, adb_state, status); -#endif - /* end of packet */ - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TACK|TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* XXX maybe clear ACK here ??? */ - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift in */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state 'idle' (end of frame) */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TACK|TIP)); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - /* - * XXX Not sure: maybe only switch to - * input mode on Talk ?? - */ - /* set to shift in */ - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - /* set ADB state idle - might get SRQ */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - } - req->sent = 1; - if (req->reply_expected) - { - /* - * maybe fake a reply here on Listen ?? - * Otherwise, a Listen hangs on success - */ - if ( macintosh_config->adb_type==MAC_ADB_II - && ((req->data[0]&0xc) == 0xc) ) - adb_state = awaiting_reply; - else if ( macintosh_config->adb_type != MAC_ADB_II - && ( req->data[0] == 0x0) - && ((req->data[1]&0xc) == 0xc) ) - adb_state = awaiting_reply; - else { - /* - * Reply expected, but none - * possible -> fake reply. - * Problem: sending next command - * should probably be done - * without setting bus to 'idle'! - * (except if no more commands) - */ -#if (ADBDEBUG & ADBDEBUG_PROT) - printk("ADB: reply expected on Listen, faking reply\n"); -#endif - /* make it look weird */ - /* XXX: return reply_len -1? */ - /* XXX: fake ADB header? */ - req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; - req->reply_len = 3; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - /* - * ready with this one, run - * next command or repeat last - * Talk (=idle on II) - */ - /* set state to idle !! */ - adb_state = idle; - if (current_req || retry_req) - adb_start(); - } - } - else - { - current_req = req->next; - if (req->done) - (*req->done)(req); - /* not sure about this */ - /* - * MS: Must set idle, no new request - * started else ! - */ - adb_state = idle; - /* - * requires setting ADB state to idle, - * maybe read a byte ! (done above) - */ - if (current_req || retry_req) - adb_start(); - } - } - else - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - req->data[data_index], adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* XXX: need to check for collision?? */ - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); -#endif - via_write(via1, vSR, req->data[data_index++]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vSR, req->data[data_index++]); - /* invert state bits, toggle ODD/EVEN */ - x = via_read(via1, vBufB); - via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); - } - } - break; - - case reading: - - /* timeout / SRQ handling for II hw */ -#ifdef POLL_ON_TIMEOUT - if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) -#else - if( (first_byte == 0xFF && (reply_len-prefix_len)==2 - && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || - ((reply_len-prefix_len)==3 - && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) -#endif - { - /* - * possible timeout (in fact, most probably a - * timeout, since SRQ can't be signaled without - * transfer on the bus). - * The last three bytes seen were FF, together - * with the starting byte (in case we started - * on 'idle' or 'awaiting_reply') this probably - * makes four. So this is mostl likely #5! - * The timeout signal is a pattern 1 0 1 0 0.. - * on /INT, meaning we missed it :-( - */ - x = via_read(via1, vSR); - if (x != 0xFF) - printk("ADB: mistaken timeout/SRQ!\n"); - - /* - * ADB status bits: either even or odd. - * adb_state: need to set 'idle' here. - * Maybe saner: set 'need_poll' or - * 'need_resend' here, fall through to - * read_done ?? - */ -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" -> read aborted: %x (%x %x)!\n", - x, adb_state, status); -#endif - -#if 0 /* XXX leave status unchanged!! - need to check this again! */ - /* XXX Only touch status on II !!! */ - /* set ADB state to idle (required by adb_start()) */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); -#endif - - /* - * What if the timeout happens on reading a - * reply ?? Assemble error reply and call - * current_request->done()? Keep request - * on queue? - */ - - /* prevent 'busy' in adb_start() */ - need_poll = 1; - - /* - * Timeout: /IRQ alternates high/low during - * 4 'FF' bytes (1 0 1 0 0...) - * We're on byte 5, so we need one - * more backlog here (TBI) .... - */ - if ((status&TREQ) != (last_status&TREQ)) { -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("ADB: reply timeout, resending!\n"); -#endif - /* - * first byte received should be the - * command byte timing out !! - */ - if (first_byte != 0xff) - command_byte = first_byte; - - /* - * compute target for retransmit: if - * last_active is set, use that one, - * else use command_byte - */ - if (last_active == -1) - last_active = (command_byte&0xf0)>>4; - adb_state = idle; - /* resend if TALK, don't poll! */ - if (current_req) - adb_start(); - else - /* - * XXX: need to count the timeouts ?? - * restart last active TALK ?? - * If no current_req, reuse old one! - */ - adb_retransmit(last_active); - - } else { - /* - * SRQ: NetBSD suggests /IRQ is asserted!? - */ - if (status&TREQ) - printk("ADB: SRQ signature w/o /INT!\n"); -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("ADB: empty SRQ packet!\n"); -#endif - /* Terminate the SRQ packet and poll */ - adb_state = idle; - adb_queue_poll(); - } - /* - * Leave ADB status lines unchanged (means /IRQ - * will still be low when entering adb_start!) - */ - break; - } - /* end timeout / SRQ handling for II hw. */ - if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) - { - /* SRQ tacked on data packet */ - /* Check /IRQ here ?? */ -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("\nADB: Packet with SRQ!\n"); -#endif - /* Terminate the packet (SRQ never ends) */ - x = via_read(via1, vSR); - adb_state = read_done; - reply_len -= 3; - reply_ptr -= 3; - need_poll = 1; - /* need to continue; next byte not seen else */ - /* - * XXX: not at all sure here; maybe need to - * send away the reply and poll immediately? - */ - } else { - /* Sanity check */ - if(reply_len>15) - reply_len=0; - /* read byte */ - *reply_ptr = via_read(via1, vSR); - x = *reply_ptr; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - *reply_ptr, adb_state, status); -#endif - reply_ptr++; - reply_len++; - } - /* The usual handshake ... */ - if (macintosh_config->adb_type==MAC_ADB_CUDA) - { - if (status == TIP) - { - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { - /* assert status == TIP | TREQ */ - if (status != TIP + TREQ) - printk("cuda: state=reading status=%x\n", status); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - else if (macintosh_config->adb_type==MAC_ADB_IISI) - { - /* ACK adb chip (maybe check for end first?) */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* end of frame?? */ - if (status & TREQ) - { -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi: end of frame!\n"); -#endif - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB) & ~(TACK|TIP)); - adb_state = read_done; - /* maybe process read_done here?? Handshake anyway?? */ - } - } - else if (macintosh_config->adb_type==MAC_ADB_II) - { - /* - * NetBSD hints that the next to last byte - * is sent with IRQ !! - * Guido found out it's the last one (0x0), - * but IRQ should be asserted already. - * Problem with timeout detection: First - * transition to /IRQ might be second - * byte of timeout packet! - * Timeouts are signaled by 4x FF. - */ - if(!(status&TREQ) && x == 0x00) /* != 0xFF */ - { -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" -> read done!\n"); -#endif -#if 0 /* XXX: we take one more byte (why?), so handshake! */ - /* set ADB state to idle */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); -#else - /* invert state bits, toggle ODD/EVEN */ - x = via_read(via1, vBufB); - via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); -#endif - /* adjust packet length */ - reply_len--; - reply_ptr--; - adb_state = read_done; - } - else - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(status!=TIP+TREQ) - printk("macII_adb: state=reading status=%x\n", status); -#endif - /* not caught: ST_CMD */ - /* required for re-entry 'reading'! */ - if ((status&ST_MASK) == ST_IDLE) { - /* (in)sanity check - set even */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - } else { - /* invert state bits, toggle ODD/EVEN */ - x = via_read(via1, vBufB); - via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); - } - } - } - break; - - case read_done: - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("ADB: read done: %x (%x %x)!\n", - x, adb_state, status); -#endif - if (reading_reply) - { - req = current_req; - req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - } - else - { - adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); - } - - /* - * remember this device ID; it's the latest we got a - * reply from! - */ - last_reply = command_byte; - last_active = (command_byte&0xf0)>>4; - - /* - * Assert status = ST_IDLE ?? - */ - /* - * SRQ seen before, initiate poll now - */ - if (need_poll) { -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("ADB: initiate poll!\n"); -#endif - adb_state = idle; - /* - * set ADB status bits?? (unchanged above!) - */ - adb_queue_poll(); - need_poll = 0; - /* hope this is ok; queue_poll runs adb_start */ - break; - } - - /* - * /IRQ seen, so the ADB controller has data for us - */ - if (!(status&TREQ)) - { - /* set ADB state to idle */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - - adb_state = reading; - reply_ptr = cuda_rbuf; - reply_len = 0; - prefix_len = 0; - if (macintosh_config->adb_type==MAC_ADB_II) { - *reply_ptr++ = ADB_PACKET; - *reply_ptr++ = command_byte; - reply_len = 2; - prefix_len = 2; - } - reading_reply = 0; - } - else - { - /* - * no IRQ, send next packet or wait - */ - adb_state = idle; - if (current_req) - adb_start(); - else - adb_retransmit(last_active); - } - break; - - default: -#if (ADBDEBUG & ADBDEBUG_STATE) - printk("adb_interrupt: unknown adb_state %d?\n", adb_state); -#endif - } - /* reset mutex and interrupts */ - driver_running = 0; - restore_flags(flags); -} - -/* - * Restart of CUDA support: please modify this interrupt handler while - * working at the Quadra etc. ADB driver. We can try to merge them later, or - * remove the CUDA stuff from the MacII handler - * - * MSch 27/01/98: Implemented IIsi driver based on initial code by Robert - * Thompson and hints from the NetBSD driver. CUDA and IIsi seem more closely - * related than to the MacII code, so merging all three might be a bad - * idea. - */ - -void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - int x, status; - struct adb_request *req; - unsigned long flags; - - save_flags(flags); - cli(); - - if(macintosh_config->adb_type==MAC_ADB_CUDA) - status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); - else - status = via_read(via1, vBufB) & (TIP|TREQ); - -#if (ADBDEBUG & ADBDEBUG_INT) - if (console_loglevel == 10) - printk("adb_interrupt: state=%d status=%x\n", adb_state, status); -#endif - - switch (adb_state) - { - case idle: - first_byte = 0; - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - /* CUDA has sent us the first byte of data - unsolicited */ - if (status != TREQ) - printk("cuda: state=idle, status=%x want=%x\n", - status, TREQ); -#endif - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_cuda: receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - udelay(150); - /* set SR to IN */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi : receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - if (status != TREQ) - printk("adb_macII: state=idle status=%x want=%x\n", - status, TREQ); - x = via_read(via1, vSR); - via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); - } - adb_state = reading; - reply_ptr = cuda_rbuf; - reply_len = 0; - reading_reply = 0; - break; - - case awaiting_reply: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - /* CUDA has sent us the first byte of data of a reply */ -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status != TREQ) - printk("cuda: state=awaiting_reply, status=%x want=%x\n", - status, TREQ); -#endif - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_cuda: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif - via_write(via1,vBufB, - via_read(via1, vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* udelay(150);*/ - /* set SR to IN */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif -#if 0 - if( via_read(via1,vBufB) & TREQ) - ending = 1; - else - ending = 0; -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - adb_state = reading; - reply_ptr = current_req->reply; - reading_reply = 1; - reply_len = 0; - break; - - case sent_first_byte: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" sending: %x (%x %x) ", - current_req->data[1], adb_state, status); -#endif - if (status == TREQ + TIP + SR_OUT) - { - /* collision */ - if (console_loglevel == 10) - printk("adb_cuda: send collision!\n"); - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TIP|TACK); - adb_state = idle; - } - else - { - /* assert status == TIP + SR_OUT */ -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status != TIP + SR_OUT) - printk("adb_cuda: state=sent_first_byte status=%x want=%x\n", - status, TIP + SR_OUT); -#endif - via_write(via1,vSR,current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index = 2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - if ( !(via_read(via1, vBufB) & TREQ) ) - { - /* collision */ -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("adb_macIIsi: send collison, aborting!\n"); -#endif - /* set shift in */ - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state to 'idle' */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TIP|TACK)); - adb_state = idle; - } - else - { - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); -#endif - via_write(via1, vSR, current_req->data[1]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - data_index=2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - if(status!=TIP+SR_OUT) - printk("adb_macII: state=send_first_byte status=%x want=%x\n", - status, TIP+SR_OUT); - via_write(via1, vSR, current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index=2; - adb_state = sending; - } - break; - - case sending: - req = current_req; - if (data_index >= req->nbytes) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" -> end (%d of %d) (%x %x)!\n", - data_index-1, req->nbytes, adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TACK|TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* XXX maybe clear ACK here ??? */ - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift in */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state 'idle' (end of frame) */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TACK|TIP)); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - } - req->sent = 1; - if (req->reply_expected) - { - /* - * maybe fake a reply here on Listen ?? - * Otherwise, a Listen hangs on success - * CUDA+IIsi: only ADB Talk considered - * RTC/PRAM read (0x1 0x3) to follow. - */ - if ( (req->data[0] == 0x0) && ((req->data[1]&0xc) == 0xc) ) - adb_state = awaiting_reply; - else { - /* - * Reply expected, but none - * possible -> fake reply. - */ -#if (ADBDEBUG & ADBDEBUG_PROT) - printk("ADB: reply expected on Listen, faking reply\n"); -#endif - /* make it look weird */ - /* XXX: return reply_len -1? */ - /* XXX: fake ADB header? */ - req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; - req->reply_len = 3; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - /* - * ready with this one, run - * next command ! - */ - /* set state to idle !! */ - adb_state = idle; - if (current_req || retry_req) - adb_start(); - } - } - else - { - current_req = req->next; - if (req->done) - (*req->done)(req); - /* not sure about this */ - adb_state = idle; - adb_start(); - } - } - else - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - req->data[data_index], adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* XXX: need to check for collision?? */ - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); -#endif - via_write(via1, vSR, req->data[data_index++]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - break; - - case reading: - if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) - { - /* Terminate the SRQ packet */ -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("adb: Got an SRQ\n"); -#endif - adb_state = idle; - adb_queue_poll(); - break; - } - /* Sanity check - botched in orig. code! */ - if(reply_len>15) { - printk("adb_cuda: reply buffer overrun!\n"); - /* wrap buffer */ - reply_len=0; - if (reading_reply) - reply_ptr = current_req->reply; - else - reply_ptr = cuda_rbuf; - } - *reply_ptr = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - *reply_ptr, adb_state, status); -#endif - reply_ptr++; - reply_len++; - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - if (status == TIP) - { - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { - /* assert status == TIP | TREQ */ -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status != TIP + TREQ) - printk("cuda: state=reading status=%x want=%x\n", - status, TIP + TREQ); -#endif - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - else if (macintosh_config->adb_type==MAC_ADB_IISI) - { - /* ACK adb chip (maybe check for end first?) */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* end of frame?? */ - if (status & TREQ) - { -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi: end of frame!\n"); -#endif - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB) & ~(TACK|TIP)); - adb_state = read_done; - /* XXX maybe process read_done here?? - Handshake anyway?? */ - } - } - if(macintosh_config->adb_type==MAC_ADB_II) - { - if( status == TIP) - { - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(status!=TIP+TREQ) - printk("macII_adb: state=reading status=%x\n", status); -#endif - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - /* fall through for IIsi on end of frame */ - if (macintosh_config->adb_type != MAC_ADB_IISI - || adb_state != read_done) - break; - - case read_done: - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb: read done: %x (%x %x)!\n", - x, adb_state, status); -#endif - if (reading_reply) - { - req = current_req; - req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - } - else - { - adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); - } - - if (macintosh_config->adb_type==MAC_ADB_CUDA - && status & TREQ) - { - via_write(via1, vBufB, - via_read(via1, vBufB)&~TIP); - adb_state = reading; - reply_ptr = cuda_rbuf; - reading_reply = 0; - } - else if (macintosh_config->adb_type==MAC_ADB_IISI - && !(status & TREQ)) - { - udelay(150); - via_write(via1, vBufB, - via_read(via1, vBufB) | TIP); - adb_state = reading; - reply_ptr = cuda_rbuf; - reading_reply = 0; - } - else - { - adb_state = idle; - adb_start(); - } - break; - - default: - printk("adb_cuda_interrupt: unknown adb_state %d?\n", adb_state); - } - - restore_flags(flags); - -} - -/* - * The 'reply delivery' routine; determines which device sent the - * request and calls the appropriate handler. - * Reply data are expected in CUDA format (again, argh...) so we need - * to fake this in the interrupt handler for MacII. - * Only one handler per device ID is currently possible. - * XXX: is the ID field here representing the default or real ID? - */ -static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs) -{ - int i, id; - - switch (buf[0]) - { - case ADB_PACKET: - /* what's in buf[1] ?? */ - id = buf[2] >> 4; -#if 0 - xmon_printf("adb packet: "); - for (i = 0; i < nb; ++i) - xmon_printf(" %x", buf[i]); - xmon_printf(", id = %d\n", id); -#endif -#if (ADBDEBUG & ADBDEBUG_INPUT) - if (console_loglevel == 10) { - printk("adb_input: adb packet "); - for (i = 0; i < nb; ++i) - printk(" %x", buf[i]); - printk(", id = %d\n", id); - } -#endif - if (adb_handler[id].handler != 0) - { - (*adb_handler[id].handler)(buf, nb, regs); - } - break; - - default: -#if (ADBDEBUG & ADBDEBUG_INPUT) - if (console_loglevel == 10) { - printk("adb_input: data from via (%d bytes):", nb); - for (i = 0; i < nb; ++i) - printk(" %.2x", buf[i]); - printk("\n"); - } -#endif - } -} - -/* Ultimately this should return the number of devices with - the given default id. */ - -int adb_register(int default_id, - void (*handler)(unsigned char *, int, struct pt_regs *)) -{ - if (adb_handler[default_id].handler != 0) - panic("Two handlers for ADB device %d\n", default_id); - adb_handler[default_id].handler = handler; - return 1; -} - -/* - * /dev/adb device driver. - */ - -#define ADB_MAJOR 56 /* major number for /dev/adb */ - -#define ADB_MAX_MINOR 64 /* range of ADB minors */ -#define ADB_TYPE_SHIFT 4 /* # bits for device ID/type in subdevices */ - -#define ADB_TYPE_RAW 0 /* raw device; unbuffered */ -#define ADB_TYPE_BUFF 1 /* raw device; buffered */ -#define ADB_TYPE_COOKED 2 /* 'cooked' device */ - - -extern void adbdev_init(void); - -struct adbdev_state { - struct adb_request req; -}; - -static DECLARE_WAIT_QUEUE_HEAD(adb_wait); - -static int adb_wait_reply(struct adbdev_state *state, struct file *file) -{ - int ret = 0; - DECLARE_WAITQUEUE(wait,current); - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&adb_wait, &wait); - - while (!state->req.got_reply) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&adb_wait, &wait); - - return ret; -} - -static void adb_write_done(struct adb_request *req) -{ - if (!req->got_reply) { - req->reply_len = 0; - req->got_reply = 1; - } - wake_up_interruptible(&adb_wait); -} - -struct file_operations *adb_raw[16]; -struct file_operations *adb_buffered[16]; -struct file_operations *adb_cooked[16]; - -static int adb_open(struct inode *inode, struct file *file) -{ - int adb_type, adb_subtype; - struct adbdev_state *state; - - if (MINOR(inode->i_rdev) > ADB_MAX_MINOR) - return -ENXIO; - - switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) { - case ADB_TYPE_RAW: - /* see code below */ - break; - case ADB_TYPE_BUFF: - /* TBI */ - return -ENXIO; - case ADB_TYPE_COOKED: - /* subtypes such as kbd, mouse, ... */ - adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT; - if ((file->f_op = adb_cooked[adb_subtype])) - return file->f_op->open(inode,file); - else - return -ENODEV; - } - - state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); - if (state == 0) - return -ENOMEM; - file->private_data = state; - state->req.reply_expected = 0; - return 0; -} - -static void adb_release(struct inode *inode, struct file *file) -{ - struct adbdev_state *state = file->private_data; - - if (state) { - file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) - if (adb_wait_reply(state, file)) - return; - kfree(state); - } - return; -} - -static int adb_lseek(struct inode *inode, struct file *file, - off_t offset, int origin) -{ - return -ESPIPE; -} - -static int adb_read(struct inode *inode, struct file *file, - char *buf, int count) -{ - int ret; - struct adbdev_state *state = file->private_data; - - if (count < 2) - return -EINVAL; - if (count > sizeof(state->req.reply)) - count = sizeof(state->req.reply); - ret = verify_area(VERIFY_WRITE, buf, count); - if (ret) - return ret; - - if (!state->req.reply_expected) - return 0; - - ret = adb_wait_reply(state, file); - if (ret) - return ret; - - state->req.reply_expected = 0; - ret = state->req.reply_len; - copy_to_user(buf, state->req.reply, ret); - - return ret; -} - -static int adb_write(struct inode *inode, struct file *file, - const char *buf, int count) -{ - int ret, i; - struct adbdev_state *state = file->private_data; - - if (count < 2 || count > sizeof(state->req.data)) - return -EINVAL; - ret = verify_area(VERIFY_READ, buf, count); - if (ret) - return ret; - - if (state->req.reply_expected && !state->req.got_reply) { - /* A previous request is still being processed. - Wait for it to finish. */ - ret = adb_wait_reply(state, file); - if (ret) - return ret; - } - - state->req.nbytes = count; - state->req.done = adb_write_done; - state->req.got_reply = 0; - copy_from_user(state->req.data, buf, count); -#if 0 - switch (adb_hardware) { - case ADB_NONE: - return -ENXIO; - case ADB_VIACUDA: - state->req.reply_expected = 1; - cuda_send_request(&state->req); - break; - default: -#endif - if (state->req.data[0] != ADB_PACKET) - return -EINVAL; - for (i = 1; i < state->req.nbytes; ++i) - state->req.data[i] = state->req.data[i+1]; - state->req.reply_expected = - ((state->req.data[0] & 0xc) == 0xc); - adb_send_request(&state->req); -#if 0 - break; - } -#endif - - return count; -} - -static struct file_operations adb_fops = { - llseek: adb_lseek, - read: adb_read, - write: adb_write, - open: adb_open, - release: adb_release, -}; - -int adbdev_register(int subtype, struct file_operations *fops) -{ - if (subtype < 0 || subtype > 15) - return -EINVAL; - if (adb_cooked[subtype]) - return -EBUSY; - adb_cooked[subtype] = fops; - return 0; -} - -int adbdev_unregister(int subtype) -{ - if (subtype < 0 || subtype > 15) - return -EINVAL; - if (!adb_cooked[subtype]) - return -ENODEV; - adb_cooked[subtype] = NULL; - return 0; -} - -void adbdev_init() -{ - if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) - printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); -} - - -#if 0 /* old ADB device */ - -/* - * Here are the file operations we export for /dev/adb. - */ - -#define ADB_MINOR 140 /* /dev/adb is c 10 140 */ - -extern void adbdev_inits(void); - -struct adbdev_state { - struct adb_request req; -}; - -static DECLARE_WAIT_QUEUE_HEAD(adb_wait); - -static int adb_wait_reply(struct adbdev_state *state, struct file *file) -{ - int ret = 0; - DECLARE_WAITQUEUE(wait, current); - -#if (ADBDEBUG & ADBDEBUG_DEVICE) - printk("ADB request: wait_reply (blocking ... \n"); -#endif - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&adb_wait, &wait); - - while (!state->req.got_reply) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&adb_wait, &wait); - - return ret; -} - -static void adb_write_done(struct adb_request *req) -{ - if (!req->got_reply) { - req->reply_len = 0; - req->got_reply = 1; - } - wake_up_interruptible(&adb_wait); -} - -static int adb_open(struct inode *inode, struct file *file) -{ - struct adbdev_state *state; - - state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); - if (state == 0) - return -ENOMEM; - file->private_data = state; - state->req.reply_expected = 0; - return 0; -} - -static void adb_release(struct inode *inode, struct file *file) -{ - struct adbdev_state *state = file->private_data; - - if (state) { - file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) - if (adb_wait_reply(state, file)) - return; - kfree(state); - } - return; -} - -static int adb_lseek(struct inode *inode, struct file *file, - off_t offset, int origin) -{ - return -ESPIPE; -} - -static int adb_read(struct inode *inode, struct file *file, - char *buf, int count) -{ - int ret; - struct adbdev_state *state = file->private_data; - - if (count < 2) - return -EINVAL; - if (count > sizeof(state->req.reply)) - count = sizeof(state->req.reply); - ret = verify_area(VERIFY_WRITE, buf, count); - if (ret) - return ret; - - if (!state->req.reply_expected) - return 0; - - ret = adb_wait_reply(state, file); - if (ret) - return ret; - - ret = state->req.reply_len; - memcpy_tofs(buf, state->req.reply, ret); - state->req.reply_expected = 0; - - return ret; -} - -static int adb_write(struct inode *inode, struct file *file, - const char *buf, int count) -{ - int ret; - struct adbdev_state *state = file->private_data; - - if (count < 2 || count > sizeof(state->req.data)) - return -EINVAL; - ret = verify_area(VERIFY_READ, buf, count); - if (ret) - return ret; - - if (state->req.reply_expected && !state->req.got_reply) { - /* A previous request is still being processed. - Wait for it to finish. */ - ret = adb_wait_reply(state, file); - if (ret) - return ret; - } - - state->req.nbytes = count; - state->req.done = adb_write_done; - memcpy_fromfs(state->req.data, buf, count); - state->req.reply_expected = 1; - state->req.got_reply = 0; - adb_send_request(&state->req); - - return count; -} - -static struct file_operations adb_fops = { - llseek: adb_lseek, - read: adb_read, - write: adb_write, - open: adb_open, - release: adb_release, -}; - -static struct miscdevice adb_dev = { - ADB_MINOR, - "adb", - &adb_fops -}; - -void adbdev_init(void) -{ - misc_register(&adb_dev); -} - -#endif /* old ADB device */ diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c new file mode 100644 index 000000000..445a99780 --- /dev/null +++ b/arch/m68k/mac/baboon.c @@ -0,0 +1,124 @@ +/* + * Baboon Custom IC Managment + * + * The Baboon custom IC controls the IDE, PCMCIA and media bay on the + * PowerBook 190. It multiplexes multiple interrupt sources onto the + * Nubus slot $C interrupt. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ide.h> + +#include <asm/traps.h> +#include <asm/bootinfo.h> +#include <asm/macintosh.h> +#include <asm/macints.h> +#include <asm/mac_baboon.h> + +/* #define DEBUG_BABOON /**/ +/* #define DEBUG_IRQS /**/ + +int baboon_present,baboon_active; +volatile struct baboon *baboon; + +void baboon_irq(int, void *, struct pt_regs *); + +extern int console_loglevel; + +extern int macide_ack_intr(ide_hwif_t *); + +/* + * Baboon initialization. + */ + +void __init baboon_init(void) +{ + if (macintosh_config->ident != MAC_MODEL_PB190) { + baboon = NULL; + baboon_present = 0; + return; + } + + baboon = (struct baboon *) BABOON_BASE; + baboon_present = 1; + baboon_active = 0; + + printk("Baboon detected at %p\n", baboon); +} + +/* + * Register the Baboon interrupt dispatcher on nubus slot $C. + */ + +void __init baboon_register_interrupts(void) +{ + request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "baboon", (void *) baboon); +} + +/* + * Baboon interrupt handler. This works a lot like a VIA. + */ + +void baboon_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit,i; + unsigned char events; + +#ifdef DEBUG_IRQS + printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n", + (uint) baboon->mb_control, (uint) baboon->mb_ifr, + (uint) baboon->mb_status, baboon_active); +#endif + + if (!(events = baboon->mb_ifr & 0x07)) return; + + for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { + if (events & irq_bit/* & baboon_active*/) { + baboon_active &= ~irq_bit; + mac_do_irq_list(IRQ_BABOON_0 + i, regs); + baboon_active |= irq_bit; + baboon->mb_ifr &= ~irq_bit; + } + } +#if 0 + if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL); + /* for now we need to smash all interrupts */ + baboon->mb_ifr &= ~events; +#endif +} + +void baboon_irq_enable(int irq) { + int irq_idx = IRQ_IDX(irq); + +#ifdef DEBUG_IRQUSE + printk("baboon_irq_enable(%d)\n", irq); +#endif + baboon_active |= (1 << irq_idx); +} + +void baboon_irq_disable(int irq) { + int irq_idx = IRQ_IDX(irq); + +#ifdef DEBUG_IRQUSE + printk("baboon_irq_disable(%d)\n", irq); +#endif + baboon_active &= ~(1 << irq_idx); +} + +void baboon_irq_clear(int irq) { + int irq_idx = IRQ_IDX(irq); + + baboon->mb_ifr &= ~(1 << irq_idx); +} + +int baboon_irq_pending(int irq) +{ + int irq_idx = IRQ_IDX(irq); + + return baboon->mb_ifr & (1 << irq_idx); +} diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index b5057f6e8..c1154b6aa 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -42,16 +42,6 @@ #include <asm/mac_oss.h> #include <asm/mac_psc.h> -/* Offset between Unix time (1970-based) and Mac time (1904-based) */ - -#define MAC_TIME_OFFSET 2082844800 - -/* - * hardware reset vector - */ - -static void (*rom_reset)(void); - /* Mac bootinfo struct */ struct mac_booter_data mac_bi_data = {0,}; @@ -76,10 +66,11 @@ extern int mackbd_init_hw(void); extern void mackbd_leds(unsigned int leds); /* Mac specific timer functions */ +extern void mac_gettod (int *, int *, int *, int *, int *, int *); extern unsigned long mac_gettimeoffset (void); -static void mac_gettod (int *, int *, int *, int *, int *, int *); -static int mac_hwclk (int, struct hwclk_time *); -static int mac_set_clock_mmss (unsigned long); +extern int mac_hwclk (int, struct hwclk_time *); +extern int mac_set_clock_mmss (unsigned long); +extern int mac_get_irq_list(char *); extern void iop_preinit(void); extern void iop_init(void); extern void via_init(void); @@ -87,6 +78,7 @@ extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); extern void via_flush_cache(void); extern void oss_init(void); extern void psc_init(void); +extern void baboon_init(void); extern void (*kd_mksound)(unsigned int, unsigned int); extern void mac_mksound(unsigned int, unsigned int); @@ -99,18 +91,6 @@ extern void nubus_sweep_video(void); extern void mac_debug_init(void); extern void mac_debugging_long(int, long); -/* poweroff functions */ -extern void via_poweroff(void); -extern void oss_poweroff(void); -extern void adb_poweroff(void); -extern void adb_hwreset(void); - -/* pram functions */ -extern __u32 via_read_time(void); -extern void via_write_time(__u32); -extern __u32 adb_read_time(void); -extern void adb_write_time(__u32); - #ifdef CONFIG_MAGIC_SYSRQ static char mac_sysrq_xlate[128] = "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */ @@ -140,186 +120,6 @@ static void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) extern int console_loglevel; -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - -/* - * This function translates seconds since 1970 into a proper date. - * - * Algorithm cribbed from glibc2.1, __offtime(). - */ -#define SECS_PER_MINUTE (60) -#define SECS_PER_HOUR (SECS_PER_MINUTE * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) - -static void unmktime(unsigned long time, long offset, - int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - /* How many days come before each month (0-12). */ - static const unsigned short int __mon_yday[2][13] = - { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - long int days, rem, y, wday, yday; - const unsigned short int *ip; - - days = time / SECS_PER_DAY; - rem = time % SECS_PER_DAY; - rem += offset; - while (rem < 0) { - rem += SECS_PER_DAY; - --days; - } - while (rem >= SECS_PER_DAY) { - rem -= SECS_PER_DAY; - ++days; - } - *hourp = rem / SECS_PER_HOUR; - rem %= SECS_PER_HOUR; - *minp = rem / SECS_PER_MINUTE; - *secp = rem % SECS_PER_MINUTE; - /* January 1, 1970 was a Thursday. */ - wday = (4 + days) % 7; /* Day in the week. Not currently used */ - if (wday < 0) wday += 7; - y = 1970; - -#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) -#define __isleap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - - while (days < 0 || days >= (__isleap (y) ? 366 : 365)) - { - /* Guess a corrected year, assuming 365 days per year. */ - long int yg = y + days / 365 - (days % 365 < 0); - - /* Adjust DAYS and Y to match the guessed year. */ - days -= ((yg - y) * 365 - + LEAPS_THRU_END_OF (yg - 1) - - LEAPS_THRU_END_OF (y - 1)); - y = yg; - } - *yearp = y - 1900; - yday = days; /* day in the year. Not currently used. */ - ip = __mon_yday[__isleap(y)]; - for (y = 11; days < (long int) ip[y]; --y) - continue; - days -= ip[y]; - *monp = y; - *dayp = days + 1; /* day in the month */ - return; -} - -/* - * Return the boot time for use in initializing the kernel clock. - * - * I'd like to read the hardware clock here but many machines read - * the PRAM through ADB, and interrupts aren't initialized when this - * is called so ADB obviously won't work. - */ - -static void mac_gettod(int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - /* Yes the GMT bias is backwards. It looks like Penguin is - screwing up the boottime it gives us... This works for me - in Canada/Eastern but it might be wrong everywhere else. */ - unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60, - yearp, monp, dayp, hourp, minp, secp); - /* For some reason this is off by one */ - *monp = *monp + 1; -} - -/* - * Read/write the hardware clock. - */ - -static int mac_hwclk(int op, struct hwclk_time *t) -{ - unsigned long now; - - if (!op) { /* read */ - if (macintosh_config->adb_type == MAC_ADB_II) { - now = via_read_time(); - } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || - (macintosh_config->adb_type == MAC_ADB_CUDA)) { - now = adb_read_time(); - } else if (macintosh_config->adb_type == MAC_ADB_IOP) { - now = via_read_time(); - } else { - now = MAC_TIME_OFFSET; - } - - now -= MAC_TIME_OFFSET; - - t->wday = 0; - unmktime(now, 0, - &t->year, &t->mon, &t->day, - &t->hour, &t->min, &t->sec); - } else { /* write */ - now = mktime(t->year + 1900, t->mon + 1, t->day, - t->hour, t->min, t->sec) + MAC_TIME_OFFSET; - - if (macintosh_config->adb_type == MAC_ADB_II) { - via_write_time(now); - } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || - (macintosh_config->adb_type == MAC_ADB_CUDA)) { - adb_write_time(now); - } else if (macintosh_config->adb_type == MAC_ADB_IOP) { - via_write_time(now); - } - } - return 0; -} - -/* - * Set minutes/seconds in the hardware clock - */ - -static int mac_set_clock_mmss (unsigned long nowtime) -{ - struct hwclk_time now; - - mac_hwclk(0, &now); - now.sec = nowtime % 60; - now.min = (nowtime / 60) % 60; - mac_hwclk(1, &now); - - return 0; -} - #if 0 void mac_waitbut (void) { @@ -330,9 +130,23 @@ void mac_waitbut (void) extern struct consw fb_con; extern struct fb_info *mac_fb_init(long *); - /* - * Parse a Macintosh-specific record in the bootinfo - */ +extern void mac_default_handler(int, void *, struct pt_regs *); + +void (*mac_handlers[8])(int, void *, struct pt_regs *)= +{ + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler +}; + +/* + * Parse a Macintosh-specific record in the bootinfo + */ int __init mac_parse_bootinfo(const struct bi_record *record) { @@ -384,9 +198,9 @@ int __init mac_parse_bootinfo(const struct bi_record *record) } /* - * Flip into 24bit mode for an instant - flushes the L2 cache card. We - * have to disable interrupts for this. Our IRQ handlers will crap - * themselves if they take an IRQ in 24bit mode! + * Flip into 24bit mode for an instant - flushes the L2 cache card. We + * have to disable interrupts for this. Our IRQ handlers will crap + * themselves if they take an IRQ in 24bit mode! */ static void mac_cache_card_flush(int writeback) @@ -414,6 +228,8 @@ void __init config_mac(void) enable_irq = mac_enable_irq; disable_irq = mac_disable_irq; mach_get_model = mac_get_model; + mach_default_handler = &mac_handlers; + mach_get_irq_list = mac_get_irq_list; mach_gettimeoffset = mac_gettimeoffset; mach_gettod = mac_gettod; mach_hwclk = mac_hwclk; @@ -489,7 +305,6 @@ struct mac_model *macintosh_config; static struct mac_model mac_data_table[]= { /* - * The default machine, in case we get an unsupported one * We'll pretend to be a Macintosh II, that's pretty safe. */ @@ -509,10 +324,6 @@ static struct mac_model mac_data_table[]= * Weirdified MacII hardware - all subtley different. Gee thanks * Apple. All these boxes seem to have VIA2 in a different place to * the MacII (+1A000 rather than +4000) - * - * The IIfx apparently has different ADB hardware, and stuff - * so zany nobody knows how to drive it. - * Even so, with Marten's help we'll try to deal with it :-) * CSA: see http://developer.apple.com/technotes/hw/hw_09.html */ @@ -584,28 +395,33 @@ static struct mac_model mac_data_table[]= { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS}, /* - * Power books - seem similar to early Quadras ? (most have 030 though) + * The PowerBooks all the same "Combo" custom IC for SCSI and SCC + * and a PMU (in two variations?) for ADB. Most of them use the + * Quadra-style VIAs. A few models also have IDE from hell. */ - { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - /* The PB150 has IDE, and IIci style VIA */ - { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - /* These have onboard SONIC */ - { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB190, "PowerBook 190", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_BABOON, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* - * Power book Duos - similar to Power books, I hope + * PowerBook Duos are pretty much like normal PowerBooks + * All of these probably have onboard SONIC in the Dock which + * means we'll have to probe for it eventually. + * + * Are these reallly MAC_VIA_IIci? The developer notes for the + * Duos show pretty much the same custom parts as in most of + * the other PowerBooks which would imply MAC_VIA_QUADRA. */ - /* All of these might have onboard SONIC in the Dock but I'm not quite sure */ { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, @@ -694,6 +510,7 @@ void mac_identify(void) via_init(); oss_init(); psc_init(); + baboon_init(); } void mac_report_hardware(void) @@ -706,137 +523,3 @@ static void mac_get_model(char *str) strcpy(str,"Macintosh "); strcat(str, macintosh_config->name); } - -/* - * The power switch - yes it's software! - */ - -void mac_poweroff(void) -{ - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (oss_present) { - oss_poweroff(); - } else if (macintosh_config->adb_type == MAC_ADB_II) { - via_poweroff(); - } else { - adb_poweroff(); - } -} - -/* - * Not all Macs support software power down; for the rest, just - * try the ROM reset vector ... - */ -void mac_reset(void) -{ - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (macintosh_config->adb_type == MAC_ADB_II) { - unsigned long cpu_flags; - - /* need ROMBASE in booter */ - /* indeed, plus need to MAP THE ROM !! */ - - if (mac_bi_data.rombase == 0) - mac_bi_data.rombase = 0x40800000; - - /* works on some */ - rom_reset = (void *) (mac_bi_data.rombase + 0xa); - - if (macintosh_config->ident == MAC_MODEL_SE30) { - /* - * MSch: Machines known to crash on ROM reset ... - */ - printk("System halted.\n"); - while(1); - } else { - save_flags(cpu_flags); - cli(); - - rom_reset(); - - restore_flags(cpu_flags); - } - - /* We never make it this far... it usually panics above. */ - printk ("Restart failed. Please restart manually.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } else if (macintosh_config->adb_type == MAC_ADB_IISI - || macintosh_config->adb_type == MAC_ADB_CUDA) { - adb_hwreset(); - } else if (CPU_IS_030) { - - /* 030-specific reset routine. The idea is general, but the - * specific registers to reset are '030-specific. Until I - * have a non-030 machine, I can't test anything else. - * -- C. Scott Ananian <cananian@alumni.princeton.edu> - */ - - unsigned long rombase = 0x40000000; - - /* make a 1-to-1 mapping, using the transparent tran. reg. */ - unsigned long virt = (unsigned long) mac_reset; - unsigned long phys = virt_to_phys(mac_reset); - unsigned long offset = phys-virt; - cli(); /* lets not screw this up, ok? */ - __asm__ __volatile__(".chip 68030\n\t" - "pmove %0,%/tt0\n\t" - ".chip 68k" - : : "m" ((phys&0xFF000000)|0x8777)); - /* Now jump to physical address so we can disable MMU */ - __asm__ __volatile__( - ".chip 68030\n\t" - "lea %/pc@(1f),%/a0\n\t" - "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ - "addl %0,%/sp\n\t" - "pflusha\n\t" - "jmp %/a0@\n\t" /* jump into physical memory */ - "0:.long 0\n\t" /* a constant zero. */ - /* OK. Now reset everything and jump to reset vector. */ - "1:\n\t" - "lea %/pc@(0b),%/a0\n\t" - "pmove %/a0@, %/tc\n\t" /* disable mmu */ - "pmove %/a0@, %/tt0\n\t" /* disable tt0 */ - "pmove %/a0@, %/tt1\n\t" /* disable tt1 */ - "movel #0, %/a0\n\t" - "movec %/a0, %/vbr\n\t" /* clear vector base register */ - "movec %/a0, %/cacr\n\t" /* disable caches */ - "movel #0x0808,%/a0\n\t" - "movec %/a0, %/cacr\n\t" /* flush i&d caches */ - "movew #0x2700,%/sr\n\t" /* set up status register */ - "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ - "movec %/a0, %/isp\n\t" - "movel %1@(0x4),%/a0\n\t" /* load reset vector */ - "reset\n\t" /* reset external devices */ - "jmp %/a0@\n\t" /* jump to the reset vector */ - ".chip 68k" - : : "r" (offset), "a" (rombase) : "a0"); - - /* should never get here */ - sti(); /* sure, why not */ - printk ("030 Restart failed. Please restart manually.\n"); - while(1); - } else { - /* We never make it here... The above shoule handle all cases. */ - printk ("Restart failed. Please restart manually.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } -} - -/* - * Local variables: - * c-indent-level: 4 - * tab-width: 8 - * End: - */ diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index 21969ce6f..3163e3ea3 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c @@ -319,7 +319,7 @@ void __init iop_register_interrupts(void) { if (iop_ism_present) { if (oss_present) { - request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, + sys_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, IRQ_FLG_LOCK, "ISM IOP", (void *) IOP_NUM_ISM); oss_irq_enable(IRQ_MAC_ADB); diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index a795d82ed..febba1982 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -35,8 +35,8 @@ * 3 - unused (?) * * 4 - SCC (slot number determined by reading RR3 on the SSC itself) - * - slot 0: SCC channel A - * - slot 1: SCC channel B + * - slot 1: SCC channel A + * - slot 2: SCC channel B * * 5 - unused (?) * [serial errors or special conditions seem to raise level 6 @@ -55,8 +55,8 @@ * - slot 5: Slot $E * * 4 - SCC IOP - * - slot 0: SCC channel A - * - slot 1: SCC channel B + * - slot 1: SCC channel A + * - slot 2: SCC channel B * * 5 - ISM IOP (ADB?) * @@ -100,19 +100,18 @@ * bits. The handlers for this new machspec interrupt number are then * called. This puts Nubus interrupts into the range 56-62. * + * - The Baboon interrupts (used on some PowerBooks) are an even more special + * case. They're hidden behind the Nubus slot $C interrupt thus adding a + * third layer of indirection. Why oh why did the Apple engineers do that? + * * - We support "fast" and "slow" handlers, just like the Amiga port. The * fast handlers are called first and with all interrupts disabled. They * are expected to execute quickly (hence the name). The slow handlers are * called last with interrupts enabled and the interrupt level restored. * They must therefore be reentrant. * - * - Drivers should never try to request autovector interrupt numbers. It - * won't work. - * * TODO: * - * o Perhaps build some intelligence into mac_SCC_handler(); we could check - * the SCC ourselves and only call the handler for the appopriate channel. */ #include <linux/types.h> @@ -125,6 +124,7 @@ #include <asm/system.h> #include <asm/irq.h> #include <asm/traps.h> +#include <asm/bootinfo.h> #include <asm/machw.h> #include <asm/macintosh.h> #include <asm/mac_via.h> @@ -133,6 +133,18 @@ #include <asm/macints.h> /* + * The mac_irq_list array is an array of linked lists of irq_node_t nodes. + * Each node contains one handler to be called whenever the interrupt + * occurs, with fast handlers listed before slow handlers. + */ + +irq_node_t *mac_irq_list[NUM_MAC_SOURCES]; + +/* SCC interrupt mask */ + +static int scc_mask; + +/* * VIA/RBV hooks */ @@ -176,6 +188,26 @@ extern int psc_irq_pending(int); extern void iop_register_interrupts(void); /* + * Baboon hooks + */ + +extern int baboon_present; + +extern void baboon_init(void); +extern void baboon_register_interrupts(void); +extern void baboon_irq_enable(int); +extern void baboon_irq_disable(int); +extern void baboon_irq_clear(int); +extern int baboon_irq_pending(int); + +/* + * SCC interrupt routines + */ + +static void scc_irq_enable(int); +static void scc_irq_disable(int); + +/* * console_loglevel determines NMI handler function */ @@ -184,17 +216,27 @@ extern int console_loglevel; extern void mac_bang(int, void *, struct pt_regs *); void mac_nmi_handler(int, void *, struct pt_regs *); -void mac_SCC_handler(int, void *, struct pt_regs *); +void mac_debug_handler(int, void *, struct pt_regs *); /* #define DEBUG_MACINTS */ void mac_init_IRQ(void) { + int i; + #ifdef DEBUG_MACINTS printk("mac_init_IRQ(): Setting things up...\n"); #endif + /* Initialize the IRQ handler lists. Initially each list is empty, */ + + for (i = 0; i < NUM_MAC_SOURCES; i++) { + mac_irq_list[i] = NULL; + } + + scc_mask = 0; + /* - * Register the handlers for the the master IRQ handlers + * Now register the handlers for the the master IRQ handlers * at levels 1-7. Most of the work is done elsewhere. */ @@ -204,8 +246,9 @@ void mac_init_IRQ(void) via_register_interrupts(); } if (psc_present) psc_register_interrupts(); + if (baboon_present) baboon_register_interrupts(); iop_register_interrupts(); - request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); + sys_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); #ifdef DEBUG_MACINTS printk("mac_init_IRQ(): Done!\n"); #endif @@ -284,27 +327,20 @@ static inline void mac_delete_irq(irq_node_t **list, void *dev_id) void mac_do_irq_list(int irq, struct pt_regs *fp) { - irq_node_t *node, *slow_nodes, **list = NULL; + irq_node_t *node, *slow_nodes; unsigned long cpu_flags; kstat.irqs[0][irq]++; - if (irq < VIA1_SOURCE_BASE) { - list = &autoirq_list[irq]; - } else if (irq < NUM_MAC_SOURCES) { - list = &userirq_list[irq - VIA1_SOURCE_BASE]; - } - if (!list) return; - #ifdef DEBUG_SPURIOUS - if (!*list && (console_loglevel > 7)) { + if (!mac_irq_list[irq] && (console_loglevel > 7)) { printk("mac_do_irq_list: spurious interrupt %d!\n", irq); return; } #endif /* serve first fast and normal handlers */ - for (node = *list; + for (node = mac_irq_list[irq]; node && (!(node->flags & IRQ_FLG_SLOW)); node = node->next) node->handler(irq, node->dev_id, fp); @@ -329,7 +365,9 @@ void mac_do_irq_list(int irq, struct pt_regs *fp) void mac_enable_irq (unsigned int irq) { - switch(IRQ_SRC(irq)) { + int irq_src = IRQ_SRC(irq); + + switch(irq_src) { case 1: via_irq_enable(irq); break; case 2: @@ -346,6 +384,12 @@ void mac_enable_irq (unsigned int irq) psc_irq_enable(irq); } else if (oss_present) { oss_irq_enable(irq); + } else if (irq_src == 4) { + scc_irq_enable(irq); + } + break; + case 8: if (baboon_present) { + baboon_irq_enable(irq); } break; } @@ -353,12 +397,13 @@ void mac_enable_irq (unsigned int irq) void mac_disable_irq (unsigned int irq) { - switch(IRQ_SRC(irq)) { + int irq_src = IRQ_SRC(irq); + + switch(irq_src) { case 1: via_irq_disable(irq); break; case 2: - case 7: - if (oss_present) { + case 7: if (oss_present) { oss_irq_disable(irq); } else { via_irq_disable(irq); @@ -371,6 +416,12 @@ void mac_disable_irq (unsigned int irq) psc_irq_disable(irq); } else if (oss_present) { oss_irq_disable(irq); + } else if (irq_src == 4) { + scc_irq_disable(irq); + } + break; + case 8: if (baboon_present) { + baboon_irq_disable(irq); } break; } @@ -397,6 +448,10 @@ void mac_clear_irq( unsigned int irq ) oss_irq_clear(irq); } break; + case 8: if (baboon_present) { + baboon_irq_clear(irq); + } + break; } } @@ -434,29 +489,37 @@ int mac_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { - int vec, ret; + irq_node_t *node; #ifdef DEBUG_MACINTS printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname); #endif if (irq < VIA1_SOURCE_BASE) { - vec = VEC_SPUR + irq; - } else if (irq < NUM_MAC_SOURCES) { - vec = VEC_USER + irq - VIA1_SOURCE_BASE; - } else { + return sys_request_irq(irq, handler, flags, devname, dev_id); + } + + if (irq >= NUM_MAC_SOURCES) { printk ("%s: unknown irq %d requested by %s\n", __FUNCTION__, irq, devname); - return -EAGAIN; } - ret = sys_request_listirq(vec, handler, flags, devname, dev_id); - if (!ret) { - vectors[vec] = autoirq_listhandler; - mac_enable_irq(irq); - } + /* Get a node and stick it onto the right list */ + + if (!(node = new_irq_node())) return -ENOMEM; + + node->handler = handler; + node->flags = flags; + node->dev_id = dev_id; + node->devname = devname; + node->next = NULL; + mac_insert_irq(&mac_irq_list[irq], node); + + /* Now enable the IRQ source */ + + mac_enable_irq(irq); - return ret; + return 0; } /* @@ -465,30 +528,120 @@ int mac_request_irq(unsigned int irq, void mac_free_irq(unsigned int irq, void *dev_id) { - irq_node_t **list = NULL; - int vec = 0; - #ifdef DEBUG_MACINTS printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id); #endif if (irq < VIA1_SOURCE_BASE) { - vec = VEC_SPUR + irq; - list = &autoirq_list[irq]; - } else if (irq < NUM_MAC_SOURCES) { - vec = VEC_USER + irq - VIA1_SOURCE_BASE; - list = &userirq_list[irq - VIA1_SOURCE_BASE]; + return sys_free_irq(irq, dev_id); + } + + if (irq >= NUM_MAC_SOURCES) { + printk ("%s: unknown irq %d freed\n", + __FUNCTION__, irq); + return; } - if (!list) return; - sys_free_irq(vec, dev_id); + mac_delete_irq(&mac_irq_list[irq], dev_id); /* If the list for this interrupt is */ /* empty then disable the source. */ - if (!*list) { + if (!mac_irq_list[irq]) { mac_disable_irq(irq); - vectors[vec] = bad_interrupt; + } +} + +/* + * Generate a pretty listing for /proc/interrupts + * + * By the time we're called the autovector interrupt list has already been + * generated, so we just need to do the machspec interrupts. + * + * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers. + * Also removed display of num_spurious it is already + * displayed for us as autovector irq 0. + */ + +int mac_get_irq_list (char *buf) +{ + int i, len = 0; + irq_node_t *node; + char *base; + + /* Don't do Nubus interrupts in this loop; we do them separately */ + /* below so that we can print slot numbers instead of IRQ numbers */ + + for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) { + + /* Nonexistant interrupt or nothing registered; skip it. */ + + if ((node = mac_irq_list[i]) == NULL) continue; + if (node->flags & IRQ_FLG_STD) continue; + + base = ""; + switch(IRQ_SRC(i)) { + case 1: base = "via1"; + break; + case 2: if (oss_present) { + base = "oss"; + } else { + base = "via2"; + } + break; + case 3: + case 4: + case 5: + case 6: if (psc_present) { + base = "psc"; + } else if (oss_present) { + base = "oss"; + } else { + if (IRQ_SRC(i) == 4) base = "scc"; + } + break; + case 7: base = "nbus"; + break; + case 8: base = "bbn"; + break; + } + len += sprintf(buf+len, "%4s %2d: %10u ", + base, i, kstat.irqs[0][i]); + + do { + if (node->flags & IRQ_FLG_FAST) { + len += sprintf(buf+len, "F "); + } else if (node->flags & IRQ_FLG_SLOW) { + len += sprintf(buf+len, "S "); + } else { + len += sprintf(buf+len, " "); + } + len += sprintf(buf+len, "%s\n", node->devname); + if ((node = node->next)) { + len += sprintf(buf+len, " "); + } + } while(node); + + } + return len; +} + +void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +#ifdef DEBUG_SPURIOUS + if (console_loglevel > 6) { + printk("Unexpected IRQ %d on device %p\n", irq, dev_id); + } +#endif +} + +static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if (num_debug[irq] < 10) { + printk("DEBUG: Unexpected IRQ %d\n", irq); + num_debug[irq]++; } } @@ -543,12 +696,53 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp) } /* - * SCC master interrupt handler; sole purpose: pass the registered - * async struct to the SCC handler proper. + * Simple routines for masking and unmasking + * SCC interrupts in cases where this can't be + * done in hardware (only the PSC can do that.) + */ + +static void scc_irq_enable(int irq) { + int irq_idx = IRQ_IDX(irq); + + scc_mask |= (1 << irq_idx); +} + +static void scc_irq_disable(int irq) { + int irq_idx = IRQ_IDX(irq); + + scc_mask &= ~(1 << irq_idx); +} + +/* + * SCC master interrupt handler. We have to do a bit of magic here + * to figure out what channel gave us the interrupt; putting this + * here is cleaner than hacking it into drivers/char/macserial.c. */ -void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs) +void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs) { - mac_do_irq_list(IRQ_SCCA, regs); - mac_do_irq_list(IRQ_SCCB, regs); + volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2; + unsigned char reg; + unsigned long cpu_flags; + + /* Read RR3 from the chip. Always do this on channel A */ + /* This must be an atomic operation so disable irqs. */ + + save_flags(cpu_flags); cli(); + *scc = 3; + reg = *scc; + restore_flags(cpu_flags); + + /* Now dispatch. Bits 0-2 are for channel B and */ + /* bits 3-5 are for channel A. We can safely */ + /* ignore the remaining bits here. */ + /* */ + /* Note that we're ignoring scc_mask for now. */ + /* If we actually mask the ints then we tend to */ + /* get hammered by very persistant SCC irqs, */ + /* and since they're autovector interrupts they */ + /* pretty much kill the system. */ + + if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs); + if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs); } diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c deleted file mode 100644 index 0d70357dc..000000000 --- a/arch/m68k/mac/mackeyb.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * linux/arch/m68k/mac/mackeyb.c - * - * Keyboard driver for Macintosh computers. - * - * Adapted from drivers/macintosh/key_mac.c and arch/m68k/atari/akakeyb.c - * (see that file for its authors and contributors). - * - * Copyright (C) 1997 Michael Schmitz. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -/* - * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c) - */ - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/kd.h> -#include <linux/tty.h> -#include <linux/console.h> -#include <linux/interrupt.h> -#include <linux/init.h> -/* keyb */ -#include <linux/keyboard.h> -#include <linux/random.h> -#include <linux/delay.h> -/* keyb */ - -#include <asm/setup.h> - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/pgtable.h> -#include <asm/machdep.h> - -#include <asm/macintosh.h> -#include <asm/macints.h> -/* for keyboard_input stuff */ -#include <asm/adb.h> -#define KEYB_KEYREG 0 /* register # for key up/down data */ -#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ -#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ -/* end keyboard_input stuff */ - -#include <linux/kbd_kern.h> -#include <linux/kbd_ll.h> - -static void kbd_repeat(unsigned long); -static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; -static int last_keycode; - -static void input_keycode(int, int); - -extern struct kbd_struct kbd_table[]; - -extern void adb_bus_init(void); -extern void handle_scancode(unsigned char, int); -extern void put_queue(int); - -/* keyb */ -static void mac_leds_done(struct adb_request *); -static void keyboard_input(unsigned char *, int, struct pt_regs *); -static void mouse_input(unsigned char *, int, struct pt_regs *); - -#ifdef CONFIG_ADBMOUSE -/* XXX: Hook for mouse driver */ -void (*adb_mouse_interrupt_hook)(unsigned char *, int); -int adb_emulate_buttons = 0; -int adb_button2_keycode = 0x7d; /* right control key */ -int adb_button3_keycode = 0x7c; /* right option key */ -#endif - -/* The mouse driver - for debugging */ -extern void adb_mouse_interrupt(char *, int); -/* end keyb */ - -/* this map indicates which keys shouldn't autorepeat. */ -static unsigned char dont_repeat[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -/* - * Mac private key maps - */ -u_short mac_plain_map[NR_KEYS] __initdata = { - 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, - 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, - 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, - 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, - 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, - 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, - 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, - 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, - 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_shift_map[NR_KEYS] __initdata = { - 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, - 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, - 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, - 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, - 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, - 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, - 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, - 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, - 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_altgr_map[NR_KEYS] __initdata = { - 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, - 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, - 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, - 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, - 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, - 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, - 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, - 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, - 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, - 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_ctrl_map[NR_KEYS] __initdata = { - 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, - 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, - 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, - 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, - 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, - 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, - 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, - 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_shift_ctrl_map[NR_KEYS] __initdata = { - 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, - 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, - 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, - 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, - 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, -}; - -u_short mac_alt_map[NR_KEYS] __initdata = { - 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, - 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, - 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, - 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, - 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, - 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, - 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, - 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, - 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, - 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, - 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_ctrl_alt_map[NR_KEYS] __initdata = { - 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, - 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, - 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, - 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, - 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, - 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, - 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -extern unsigned int keymap_count; - -/* - * Misc. defines for testing - */ - -extern int console_loglevel; - -static struct adb_request led_request; -extern int in_keybinit; - -/* - * machdep keyboard routines, interface and key repeat method modeled after - * drivers/macintosh/keyb_mac.c - */ - -int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep, - char raw_mode) -{ - if (!raw_mode) { - /* - * Convert R-shift/control/option to L version. - * Remap keycode 0 (A) to the unused keycode 0x5a. - * Other parts of the system assume 0 is not a valid keycode. - */ - switch (keycode) { - case 0x7b: keycode = 0x38; break; /* R-shift */ - case 0x7c: keycode = 0x3a; break; /* R-option */ - case 0x7d: keycode = 0x36; break; /* R-control */ - case 0: keycode = 0x5a; break; /* A */ - } - } - *keycodep = keycode; - return 1; -} - -int mac_kbd_unexpected_up(unsigned char keycode) -{ - return 0x80; -} - -static void -keyboard_input(unsigned char *data, int nb, struct pt_regs *regs) -{ - /* first check this is from register 0 */ - if (nb != 5 || (data[2] & 3) != KEYB_KEYREG) - return; /* ignore it */ - kbd_pt_regs = regs; - input_keycode(data[3], 0); - if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f))) - input_keycode(data[4], 0); -} - -static void -input_keycode(int keycode, int repeat) -{ - struct kbd_struct *kbd; - int up_flag; - - kbd = kbd_table + fg_console; - up_flag = (keycode & 0x80); - keycode &= 0x7f; - - if (!repeat) - del_timer(&repeat_timer); - -#ifdef CONFIG_ADBMOUSE - /* - * XXX: Add mouse button 2+3 fake codes here if mouse open. - * As we only report up/down events, keep track of faked buttons. - * Really messy; might need to check if keyboard is in - * VC_RAW mode for X?. - * Might also want to know how many buttons need to be emulated. - * -> hide this as function in arch/m68k/mac ? - * Current emulation buttons: right alt/option and control - * (wanted: command and alt/option, or KP= and KP( ...) - * Debug version; might be rewritten to be faster on normal keys. - */ - if (adb_emulate_buttons - && (adb_mouse_interrupt_hook || console_loglevel >= 8)) { - unsigned char button, button2, button3, fake_event; - static unsigned char button2state=0, button3state=0; /* up */ - /* faked ADB packet */ - static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 }; - - button = 0; - fake_event = 0; - if (keycode == adb_button2_keycode) { /* which 'button' ? */ - /* R-option */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - } else if (keycode == adb_button3_keycode) { - /* R-control */ - button3 = (!up_flag); /* new state */ - if (button3 != button3state) /* change ? */ - button = 3; - button3state = button3; /* save state */ - fake_event = 3; - } -#ifdef DEBUG_ADBMOUSE - if (fake_event && console_loglevel >= 8) - printk("fake event: button2 %d button3 %d button %d\n", - button2state, button3state, button); -#endif - if (button) { /* there's been a button state change */ - /* fake a mouse packet : send all bytes, change one! */ - data[button] = (up_flag ? 0x80 : 0); - if (adb_mouse_interrupt_hook) - adb_mouse_interrupt_hook(data, 4); -#ifdef DEBUG_ADBMOUSE - else - printk("mouse_fake: data %2x %2x %2x buttons %2x \n", - data[1], data[2], data[3], - ~( (data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2) )&7 ); -#endif - } - /* - * for mouse 3-button emulation: don't process 'fake' keys! - * Keys might autorepeat, and console state gets generally messed - * up enough so that selection stops working. - */ - if (fake_event) - return; - } -#endif /* CONFIG_ADBMOUSE */ - - /* - * Convert R-shift/control/option to L version. - */ - switch (keycode) { - case 0x7b: keycode = 0x38; break; /* R-shift */ - case 0x7c: keycode = 0x3a; break; /* R-option */ - case 0x7d: keycode = 0x36; break; /* R-control */ - case 0x0: if (kbd->kbdmode != VC_RAW) - keycode = 0x5a; /* A; keycode 0 deprecated */ - break; - } - - if (kbd->kbdmode != VC_RAW) { - if (!up_flag && !dont_repeat[keycode]) { - last_keycode = keycode; - repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2); - add_timer(&repeat_timer); - } - - /* - * XXX fix caps-lock behaviour by turning the key-up - * transition into a key-down transition. - * MSch: need to turn each caps-lock event into a down-up - * double event (keyboard code assumes caps-lock is a toggle) - * 981127: fix LED behavior (kudos atong!) - */ - switch (keycode) { - case 0x39: - handle_scancode(keycode, 1); /* down */ - up_flag = 0x80; /* see below ... */ - mark_bh(KEYBOARD_BH); - break; - case 0x47: - mark_bh(KEYBOARD_BH); - break; - } - } - - handle_scancode(keycode, !up_flag); -} - -static void -kbd_repeat(unsigned long xxx) -{ - unsigned long flags; - - save_flags(flags); - cli(); - input_keycode(last_keycode, 1); - restore_flags(flags); -} - - /* [ACA:23-Mar-97] Three button mouse support. This is designed to - function with MkLinux DR-2.1 style X servers. It only works with - three-button mice that conform to Apple's multi-button mouse - protocol. */ - - /* - The X server for MkLinux DR2.1 uses the following unused keycodes to - read the mouse: - - 0x7e This indicates that the next two keycodes should be interpreted - as mouse information. The first following byte's high bit - represents the state of the left button. The lower seven bits - represent the x-axis acceleration. The lower seven bits of the - second byte represent y-axis acceleration. - - 0x3f The x server interprets this keycode as a middle button - release. - - 0xbf The x server interprets this keycode as a middle button - depress. - - 0x40 The x server interprets this keycode as a right button - release. - - 0xc0 The x server interprets this keycode as a right button - depress. - - NOTES: There should be a better way of handling mice in the X server. - The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead - of two. The three mouse buttons should then, in the X server, be read - as the high-bits of all three bytes. The x and y motions can still be - in the first two bytes. Maybe I'll do this... - */ - - /* - Handler 4 -- Apple Extended mouse protocol. - - For Apple's 3-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = 0100 0000 Extended protocol register. - Bits 6-7 are the device id, which should be 1. - Bits 4-5 are resolution which is in "units/inch". - The Logitech MouseMan returns these bits clear but it has - 200/300cpi resolution. - Bits 0-3 are unique vendor id. - data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. - Bits 2-3 should be 8 + 4. - Bits 4-7 should be 3 for a mouse device. - data[3] = bxxx xxxx Left button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - data[5] = byyy bxxx Third button and fourth button. Y is additional - high bits of y-axis motion. XY is additional - high bits of x-axis motion. - - NOTE: data[0] and data[2] are confirmed by the parent function and - need not be checked here. - */ - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = ???? ???? (?) - data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. - data[3] = bxxx xxxx First button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - - NOTE: data[0] is confirmed by the parent function and need not be - checked here. - */ - -static void -mouse_input(unsigned char *data, int nb, struct pt_regs *regs) -{ - struct kbd_struct *kbd; - int i; - - if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) { - printk("data from mouse:"); - for (i = 0; i < nb; ++i) - printk(" %x", data[i]); - printk("\n"); - return; - } - - if (adb_mouse_interrupt_hook) { - adb_mouse_interrupt_hook(data+2, nb-2); - /* - * passing the mouse data to i.e. the X server as done for - * Xpmac will confuse applications on a sane X server :-) - */ - return; - } -#ifdef DEBUG_ADBMOUSE - else - if (console_loglevel >= 8) - printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", - data[3], data[4], data[5], - ~((data[3] & 0x80 ? 0 : 4) - | (data[4] & 0x80 ? 0 : 1) - | (data[5] & 0x80 ? 0 : 2))&7, - ((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ), - ((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) ); -#endif - - - kbd = kbd_table + fg_console; - -#if 0 /* The entirely insane way of MkLinux handling mouse input */ - /* Requires put_queue which is static in keyboard.c :-( */ - /* Only send mouse codes when keyboard is in raw mode. */ - if (kbd->kbdmode == VC_RAW) { - static unsigned char uch_ButtonStateSecond = 0; - unsigned char uchButtonSecond; - - /* Send first button, second button and movement. */ - put_queue( 0x7e ); - put_queue( data[3] ); - put_queue( data[4] ); - - /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ - - /* Store the button state. */ - uchButtonSecond = (data[4] & 0x80); - - /* Send second button. */ - if (uchButtonSecond != uch_ButtonStateSecond) { - put_queue( 0x3f | uchButtonSecond ); - uch_ButtonStateSecond = uchButtonSecond; - } - - /* Macintosh 3-button mouse (handler 4). */ - if ((nb == 6) && (data[1] & 0x40)) { - static unsigned char uch_ButtonStateThird = 0; - unsigned char uchButtonThird; - - /* Store the button state for speed. */ - uchButtonThird = (data[5] & 0x80); - - /* Send third button. */ - if (uchButtonThird != uch_ButtonStateThird) { - put_queue( 0x40 | uchButtonThird ); - uch_ButtonStateThird = uchButtonThird; - } - } - } -#endif /* insane MkLinux mouse hack */ -} - -/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ -static unsigned char mac_ledmap[8] = { - 0, /* none */ - 4, /* scroll lock */ - 1, /* num lock */ - 5, /* scroll + num lock */ - 2, /* caps lock */ - 6, /* caps + scroll lock */ - 3, /* caps + num lock */ - 7, /* caps + num + scroll lock */ -}; - -static int leds_pending; - -void mac_kbd_leds(unsigned int leds) -{ - if (led_request.got_reply) { -#ifdef DEBUG_ADB - if (console_loglevel == 10) - printk("mac_kbd_leds: got reply, sending request!\n"); -#endif - adb_request(&led_request, mac_leds_done, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), - 0xff, ~mac_ledmap[leds]); - } else - leds_pending = leds | 0x100; -} - -static void mac_leds_done(struct adb_request *req) -{ - int leds; - - if (leds_pending) { - leds = leds_pending & 0xff; - leds_pending = 0; - mac_kbd_leds(leds); - } - mark_bh(KEYBOARD_BH); -} - -int mac_kbdrate(struct kbd_repeat *k) -{ - return 0; -} - -int __init mac_keyb_init(void) -{ - static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req; - volatile int ct; - - /* setup key map */ - memcpy(key_maps[0], mac_plain_map, sizeof(plain_map)); - memcpy(key_maps[1], mac_shift_map, sizeof(plain_map)); - memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map)); - memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map)); - memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map)); - memcpy(key_maps[8], mac_alt_map, sizeof(plain_map)); - memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map)); - - /* initialize mouse interrupt hook */ - adb_mouse_interrupt_hook = NULL; - - /* - * Might put that someplace else, possibly .... - */ - adb_bus_init(); - - /* the input functions ... */ - adb_register(ADB_KEYBOARD, keyboard_input); - adb_register(ADB_MOUSE, mouse_input); - - /* turn on ADB auto-polling in the CUDA */ - - /* - * Older boxes don't support CUDA_* targets and CUDA commands - * instead we emulate them in the adb_request hook to make - * the code interfaces saner. - * - * Note XXX: the Linux PMac and this code both assume the - * devices are at their primary ids and do not do device - * assignment. This isn't ideal. We should fix it to follow - * the reassignment specs. - */ - - if (macintosh_config->adb_type == MAC_ADB_CUDA) { - printk("CUDA autopoll on ...\n"); - adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); - ct=0; - while (!autopoll_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("Keyboard timed out.\n"); - autopoll_req.got_reply = 1; - } - } - - /* - * XXX: all ADB requests now in CUDA format; adb_request takes - * care of that for other Macs. - */ - - printk("Configuring keyboard:\n"); - - udelay(3000); - - /* - * turn on all leds - the keyboard driver will turn them back off - * via mac_kbd_leds if everything works ok! - */ - printk("leds on ...\n"); - adb_request(&led_request, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7); - - /* - * The polling stuff should go away as soon as the ADB driver is stable - */ - ct = 0; - while (!led_request.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("keyboard timed out.\n"); - led_request.got_reply = 1; - } - -#if 1 - printk("configuring coding mode ...\n"); - - udelay(3000); - - /* - * get the keyboard to send separate codes for - * left and right shift, control, option keys. - */ - adb_request(&confcod_req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); - - ct=0; - while (!confcod_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("keyboard timed out.\n"); - confcod_req.got_reply = 1; - } -#endif - -#if 0 /* seems to hurt, at least Geert's Mac */ - printk("Configuring mouse (3-button mode) ...\n"); - - udelay(3000); - - /* - * XXX: taken from the PPC driver again ... - * Try to switch the mouse (id 3) to handler 4, for three-button - * mode. (0x20 is Service Request Enable, 0x03 is Device ID). - */ - adb_request(&mouse_req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); - - ct=0; - while (!mouse_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) - printk("Mouse timed out.\n"); -#endif - -#if 0 - printk("Start polling keyboard ...\n"); - - /* - * get the keyboard to send data back, via the adb_input hook - * XXX: was never used properly, and the driver takes care - * of polling and timeout retransmits now. - * Might be of use if we want to start talking to a specific - * device here... - */ - adb_request(&readkey_req, NULL, 2, ADB_PACKET, - ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG)); -#endif - - in_keybinit = 0; - printk("keyboard init done\n"); - - return 0; -} diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c new file mode 100644 index 000000000..a14f25c56 --- /dev/null +++ b/arch/m68k/mac/misc.c @@ -0,0 +1,689 @@ +/* + * Miscellaneous Mac68K-specific stuff + */ + +#include <stdarg.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/kd.h> +#include <linux/mm.h> + +#include <linux/adb.h> +#include <linux/cuda.h> +#include <linux/pmu.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/segment.h> +#include <asm/setup.h> +#include <asm/macintosh.h> +#include <asm/mac_via.h> +#include <asm/mac_oss.h> + +#define BOOTINFO_COMPAT_1_0 +#include <asm/bootinfo.h> +#include <asm/machdep.h> + +/* Offset between Unix time (1970-based) and Mac time (1904-based) */ + +#define RTC_OFFSET 2082844800 + +extern struct mac_booter_data mac_bi_data; +static void (*rom_reset)(void); + +/* + * Return the current time as the number of seconds since January 1, 1904. + */ + +static long adb_read_time(void) +{ + volatile struct adb_request req; + long time; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 2, CUDA_PACKET, CUDA_GET_TIME); + + time = (req.reply[3] << 24) | (req.reply[4] << 16) + | (req.reply[5] << 8) | req.reply[6]; + return time - RTC_OFFSET; +} + +/* + * Set the current system time + */ + +static void adb_write_time(long data) +{ + volatile struct adb_request req; + + data += RTC_OFFSET; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 6, CUDA_PACKET, CUDA_SET_TIME, + (data >> 24) & 0xFF, (data >> 16) & 0xFF, + (data >> 8) & 0xFF, data & 0xFF); +} + +/* + * Get a byte from the NVRAM + */ + +static __u8 adb_read_pram(int offset) +{ + volatile struct adb_request req; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 4, CUDA_PACKET, CUDA_GET_PRAM, + (offset >> 8) & 0xFF, offset & 0xFF); + return req.reply[3]; +} + +/* + * Write a byte to the NVRAM + */ + +static void adb_write_pram(int offset, __u8 data) +{ + volatile struct adb_request req; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 5, CUDA_PACKET, CUDA_SET_PRAM, + (offset >> 8) & 0xFF, offset & 0xFF, + data); +} + +/* + * VIA PRAM/RTC access routines + * + * Must be called with interrupts disabled and + * the RTC should be enabled. + */ + +static __u8 via_pram_readbyte(void) +{ + int i,reg; + __u8 data; + + reg = via1[vBufB] & ~VIA1B_vRTCClk; + + /* Set the RTC data line to be an input. */ + + via1[vDirB] &= ~VIA1B_vRTCData; + + /* The bits of the byte come out in MSB order */ + + data = 0; + for (i = 0 ; i < 8 ; i++) { + via1[vBufB] = reg; + via1[vBufB] = reg | VIA1B_vRTCClk; + data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData); + } + + /* Return RTC data line to output state */ + + via1[vDirB] |= VIA1B_vRTCData; + + return data; +} + +static void via_pram_writebyte(__u8 data) +{ + int i,reg,bit; + + reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData); + + /* The bits of the byte go in in MSB order */ + + for (i = 0 ; i < 8 ; i++) { + bit = data & 0x80? 1 : 0; + data <<= 1; + via1[vBufB] = reg | bit; + via1[vBufB] = reg | bit | VIA1B_vRTCClk; + } +} + +/* + * Execute a VIA PRAM/RTC command. For read commands + * data should point to a one-byte buffer for the + * resulting data. For write commands it should point + * to the data byte to for the command. + * + * This function disables all interrupts while running. + */ + +static void via_pram_command(int command, __u8 *data) +{ + unsigned long cpu_flags; + int is_read; + + save_flags(cpu_flags); + cli(); + + /* Enable the RTC and make sure the strobe line is high */ + + via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb; + + if (command & 0xFF00) { /* extended (two-byte) command */ + via_pram_writebyte((command & 0xFF00) >> 8); + via_pram_writebyte(command & 0xFF); + is_read = command & 0x8000; + } else { /* one-byte command */ + via_pram_writebyte(command); + is_read = command & 0x80; + } + if (is_read) { + *data = via_pram_readbyte(); + } else { + via_pram_writebyte(*data); + } + + /* All done, disable the RTC */ + + via1[vBufB] |= VIA1B_vRTCEnb; + + restore_flags(cpu_flags); +} + +static __u8 via_read_pram(int offset) +{ + return 0; +} + +static void via_write_pram(int offset, __u8 data) +{ +} + +/* + * Return the current time in seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +static long via_read_time(void) +{ + union { + __u8 cdata[4]; + long idata; + } result, last_result; + int ct; + + /* + * The NetBSD guys say to loop until you get the same reading + * twice in a row. + */ + + ct = 0; + do { + if (++ct > 10) { + printk("via_read_time: couldn't get valid time, " + "last read = 0x%08X and 0x%08X\n", last_result.idata, + result.idata); + break; + } + + last_result.idata = result.idata; + result.idata = 0; + + via_pram_command(0x81, &result.cdata[3]); + via_pram_command(0x85, &result.cdata[2]); + via_pram_command(0x89, &result.cdata[1]); + via_pram_command(0x8D, &result.cdata[0]); + } while (result.idata != last_result.idata); + + return result.idata - RTC_OFFSET; +} + +/* + * Set the current time to a number of seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +static void via_write_time(long time) +{ + union { + __u8 cdata[4]; + long idata; + } data; + __u8 temp; + + /* Clear the write protect bit */ + + temp = 0x55; + via_pram_command(0x35, &temp); + + data.idata = time + RTC_OFFSET; + via_pram_command(0x01, &data.cdata[3]); + via_pram_command(0x05, &data.cdata[2]); + via_pram_command(0x09, &data.cdata[1]); + via_pram_command(0x0D, &data.cdata[0]); + + /* Set the write protect bit */ + + temp = 0xD5; + via_pram_command(0x35, &temp); +} + +static void via_shutdown(void) +{ + if (rbv_present) { + via2[rBufB] &= ~0x04; + } else { + /* Direction of vDirB is output */ + via2[vDirB] |= 0x04; + /* Send a value of 0 on that line */ + via2[vBufB] &= ~0x04; + mdelay(1000); + } +} + +/* + * FIXME: not sure how this is supposed to work exactly... + */ + +static void oss_shutdown(void) +{ + oss->rom_ctrl = OSS_POWEROFF; +} + +#ifdef CONFIG_ADB_CUDA + +static void cuda_restart(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 2, CUDA_PACKET, CUDA_RESET_SYSTEM); +} + +static void cuda_shutdown(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 2, CUDA_PACKET, CUDA_POWERDOWN); +} + +#endif /* CONFIG_ADB_CUDA */ + +#ifdef CONFIG_ADB_PMU + +void pmu_restart(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 3, PMU_PACKET, PMU_SET_INTR_MASK, + PMU_INT_ADB|PMU_INT_TICK); + + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 2, PMU_PACKET, PMU_RESET); +} + +void pmu_shutdown(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 3, PMU_PACKET, PMU_SET_INTR_MASK, + PMU_INT_ADB|PMU_INT_TICK); + + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 6, PMU_PACKET, PMU_SHUTDOWN, + 'M', 'A', 'T', 'T'); +} + +#endif /* CONFIG_ADB_PMU */ + +/* + *------------------------------------------------------------------- + * Below this point are the generic routines; they'll dispatch to the + * correct routine for the hardware on which we're running. + *------------------------------------------------------------------- + */ + +void mac_pram_read(int offset, __u8 *buffer, int len) +{ + __u8 (*func)(int) = NULL; + int i; + + if (macintosh_config->adb_type == MAC_ADB_IISI || + macintosh_config->adb_type == MAC_ADB_PB1 || + macintosh_config->adb_type == MAC_ADB_PB2 || + macintosh_config->adb_type == MAC_ADB_CUDA) { + func = adb_read_pram; + } else { + func = via_read_pram; + } + for (i = 0 ; i < len ; i++) { + buffer[i] = (*func)(offset++); + } +} + +void mac_pram_write(int offset, __u8 *buffer, int len) +{ + void (*func)(int, __u8) = NULL; + int i; + + if (macintosh_config->adb_type == MAC_ADB_IISI || + macintosh_config->adb_type == MAC_ADB_PB1 || + macintosh_config->adb_type == MAC_ADB_PB2 || + macintosh_config->adb_type == MAC_ADB_CUDA) { + func = adb_write_pram; + } else { + func = via_write_pram; + } + for (i = 0 ; i < len ; i++) { + (*func)(offset++, buffer[i]); + } +} + +void mac_poweroff(void) +{ + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ + + if (oss_present) { + oss_shutdown(); + } else if (macintosh_config->adb_type == MAC_ADB_II) { + via_shutdown(); +#ifdef CONFIG_ADB_CUDA + } else if (macintosh_config->adb_type == MAC_ADB_CUDA) { + cuda_shutdown(); +#endif +#ifdef CONFIG_ADB_PMU + } else if (macintosh_config->adb_type == MAC_ADB_PB1 + || macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_shutdown(); +#endif + } + sti(); + printk("It is now safe to turn off your Macintosh.\n"); + while(1); +} + +void mac_reset(void) +{ + if (macintosh_config->adb_type == MAC_ADB_II) { + unsigned long cpu_flags; + + /* need ROMBASE in booter */ + /* indeed, plus need to MAP THE ROM !! */ + + if (mac_bi_data.rombase == 0) + mac_bi_data.rombase = 0x40800000; + + /* works on some */ + rom_reset = (void *) (mac_bi_data.rombase + 0xa); + + if (macintosh_config->ident == MAC_MODEL_SE30) { + /* + * MSch: Machines known to crash on ROM reset ... + */ + } else { + save_flags(cpu_flags); + cli(); + + rom_reset(); + + restore_flags(cpu_flags); + } +#ifdef CONFIG_ADB_CUDA + } else if (macintosh_config->adb_type == MAC_ADB_CUDA) { + cuda_restart(); +#endif +#ifdef CONFIG_ADB_PMU + } else if (macintosh_config->adb_type == MAC_ADB_PB1 + || macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_restart(); +#endif + } else if (CPU_IS_030) { + + /* 030-specific reset routine. The idea is general, but the + * specific registers to reset are '030-specific. Until I + * have a non-030 machine, I can't test anything else. + * -- C. Scott Ananian <cananian@alumni.princeton.edu> + */ + + unsigned long rombase = 0x40000000; + + /* make a 1-to-1 mapping, using the transparent tran. reg. */ + unsigned long virt = (unsigned long) mac_reset; + unsigned long phys = virt_to_phys(mac_reset); + unsigned long offset = phys-virt; + cli(); /* lets not screw this up, ok? */ + __asm__ __volatile__(".chip 68030\n\t" + "pmove %0,%/tt0\n\t" + ".chip 68k" + : : "m" ((phys&0xFF000000)|0x8777)); + /* Now jump to physical address so we can disable MMU */ + __asm__ __volatile__( + ".chip 68030\n\t" + "lea %/pc@(1f),%/a0\n\t" + "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ + "addl %0,%/sp\n\t" + "pflusha\n\t" + "jmp %/a0@\n\t" /* jump into physical memory */ + "0:.long 0\n\t" /* a constant zero. */ + /* OK. Now reset everything and jump to reset vector. */ + "1:\n\t" + "lea %/pc@(0b),%/a0\n\t" + "pmove %/a0@, %/tc\n\t" /* disable mmu */ + "pmove %/a0@, %/tt0\n\t" /* disable tt0 */ + "pmove %/a0@, %/tt1\n\t" /* disable tt1 */ + "movel #0, %/a0\n\t" + "movec %/a0, %/vbr\n\t" /* clear vector base register */ + "movec %/a0, %/cacr\n\t" /* disable caches */ + "movel #0x0808,%/a0\n\t" + "movec %/a0, %/cacr\n\t" /* flush i&d caches */ + "movew #0x2700,%/sr\n\t" /* set up status register */ + "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ + "movec %/a0, %/isp\n\t" + "movel %1@(0x4),%/a0\n\t" /* load reset vector */ + "reset\n\t" /* reset external devices */ + "jmp %/a0@\n\t" /* jump to the reset vector */ + ".chip 68k" + : : "r" (offset), "a" (rombase) : "a0"); + } + + /* should never get here */ + sti(); + printk ("Restart failed. Please restart manually.\n"); + while(1); +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +/* + * This function translates seconds since 1970 into a proper date. + * + * Algorithm cribbed from glibc2.1, __offtime(). + */ +#define SECS_PER_MINUTE (60) +#define SECS_PER_HOUR (SECS_PER_MINUTE * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +static void unmktime(unsigned long time, long offset, + int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + /* How many days come before each month (0-12). */ + static const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + long int days, rem, y, wday, yday; + const unsigned short int *ip; + + days = time / SECS_PER_DAY; + rem = time % SECS_PER_DAY; + rem += offset; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + *hourp = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + *minp = rem / SECS_PER_MINUTE; + *secp = rem % SECS_PER_MINUTE; + /* January 1, 1970 was a Thursday. */ + wday = (4 + days) % 7; /* Day in the week. Not currently used */ + if (wday < 0) wday += 7; + y = 1970; + +#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) +#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + + while (days < 0 || days >= (__isleap (y) ? 366 : 365)) + { + /* Guess a corrected year, assuming 365 days per year. */ + long int yg = y + days / 365 - (days % 365 < 0); + + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + *yearp = y - 1900; + yday = days; /* day in the year. Not currently used. */ + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + *monp = y; + *dayp = days + 1; /* day in the month */ + return; +} + +/* + * Return the boot time for use in initializing the kernel clock. + * + * I'd like to read the hardware clock here but many machines read + * the PRAM through ADB, and interrupts aren't initialized when this + * is called so ADB obviously won't work. + */ + +void mac_gettod(int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + /* Yes the GMT bias is backwards. It looks like Penguin is + screwing up the boottime it gives us... This works for me + in Canada/Eastern but it might be wrong everywhere else. */ + unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60, + yearp, monp, dayp, hourp, minp, secp); + /* For some reason this is off by one */ + *monp = *monp + 1; +} + +/* + * Read/write the hardware clock. + */ + +int mac_hwclk(int op, struct hwclk_time *t) +{ + unsigned long now; + + if (!op) { /* read */ + if (macintosh_config->adb_type == MAC_ADB_II) { + now = via_read_time(); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_PB1) || + (macintosh_config->adb_type == MAC_ADB_PB2) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + now = adb_read_time(); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + now = via_read_time(); + } else { + now = 0; + } + + t->wday = 0; + unmktime(now, 0, + &t->year, &t->mon, &t->day, + &t->hour, &t->min, &t->sec); + printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n", + t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec); + } else { /* write */ + printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n", + t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec); + +#if 0 /* it trashes my rtc */ + now = mktime(t->year + 1900, t->mon + 1, t->day, + t->hour, t->min, t->sec); + + if (macintosh_config->adb_type == MAC_ADB_II) { + via_write_time(now); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_PB1) || + (macintosh_config->adb_type == MAC_ADB_PB2) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + adb_write_time(now); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + via_write_time(now); + } +#endif + } + return 0; +} + +/* + * Set minutes/seconds in the hardware clock + */ + +int mac_set_clock_mmss (unsigned long nowtime) +{ + struct hwclk_time now; + + mac_hwclk(0, &now); + now.sec = nowtime % 60; + now.min = (nowtime / 60) % 60; + mac_hwclk(1, &now); + + return 0; +} diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index 442d72802..c405fc0da 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -34,7 +34,7 @@ void oss_irq(int, void *, struct pt_regs *); void oss_nubus_irq(int, void *, struct pt_regs *); extern void via1_irq(int, void *, struct pt_regs *); -extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern void mac_scc_dispatch(int, void *, struct pt_regs *); extern int console_loglevel; /* @@ -68,16 +68,16 @@ void __init oss_init(void) void __init oss_register_interrupts(void) { - request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, - "OSS SCSI Dispatch", (void *) oss); - request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK, - "SCC Dispatch", mac_SCC_handler); - request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, - "Nubus Dispatch", (void *) oss); - request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, - "OSS Sound Dispatch", (void *) oss); - request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, - "VIA1 Dispatch", (void *) via1); + sys_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, + "scsi", (void *) oss); + sys_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK, + "scc", mac_scc_dispatch); + sys_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, + "nubus", (void *) oss); + sys_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, + "sound", (void *) oss); + sys_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, + "via1", (void *) via1); } /* @@ -89,22 +89,6 @@ void __init oss_nubus_init(void) } /* - * Turn off the power via the ROM control register - * - * FIXME: not sure how this is supposed to work exactly... - */ - -void oss_poweroff(void) -{ - oss->rom_ctrl = OSS_POWEROFF; - - /* We should never make it this far... */ - - printk ("It is now safe to switch off your machine.\n"); - while(1); -} - -/* * Handle miscellaneous OSS interrupts. Right now that's just sound * and SCSI; everything else is routed to its own autovector IRQ. */ diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index 45825b113..86bbf72cc 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -119,14 +119,14 @@ void __init psc_init(void) void __init psc_register_interrupts(void) { - request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x30); - request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x40); - request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x50); - request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x60); + sys_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", + (void *) 0x30); + sys_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", + (void *) 0x40); + sys_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", + (void *) 0x50); + sys_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", + (void *) 0x60); } /* diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 2205b226c..af001907d 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -24,6 +24,8 @@ #include <linux/delay.h> #include <linux/init.h> +#include <linux/ide.h> + #include <asm/traps.h> #include <asm/bootinfo.h> #include <asm/macintosh.h> @@ -60,7 +62,7 @@ static int gIER,gIFR,gBufA,gBufB; #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -static int nubus_active; +static int nubus_active = 0; void via_debug_dump(void); void via1_irq(int, void *, struct pt_regs *); @@ -71,7 +73,7 @@ void via_irq_disable(int irq); void via_irq_clear(int irq); extern void mac_bang(int, void *, struct pt_regs *); -extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern void mac_scc_dispatch(int, void *, struct pt_regs *); extern int console_loglevel; extern int oss_present; @@ -260,28 +262,28 @@ void __init via_init_clock(void (*func)(int, void *, struct pt_regs *)) void __init via_register_interrupts(void) { if (via_alt_mapping) { - request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "Software IRQ", (void *) via1); - request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "VIA1 Dispatch", (void *) via1); + sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "software", (void *) via1); + sys_request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "via1", (void *) via1); } else { - request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "VIA1 Dispatch", (void *) via1); + sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "via1", (void *) via1); #if 0 /* interferes with serial on some machines */ if (!psc_present) { - request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, + sys_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, "Off Switch", mac_bang); } #endif } - request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "VIA2 Dispatch", (void *) via2); + sys_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "via2", (void *) via2); if (!psc_present) { - request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK, - "SCC Dispatch", mac_SCC_handler); + sys_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK, + "scc", mac_scc_dispatch); } request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "Nubus Dispatch", (void *) via2); + "nubus", (void *) via2); } /* @@ -361,34 +363,13 @@ int via_get_cache_disable(void) } /* - * VIA-based power switch, for machines that support it. - */ - -void via_poweroff(void) -{ - if (rbv_present) { - via2[rBufB] &= ~0x04; - } else { - /* Direction of vDirB is output */ - via2[vDirB] |= 0x04; - /* Send a value of 0 on that line */ - via2[vBufB] &= ~0x04; - /* Otherwise it prints "It is now.." then shuts off */ - mdelay(1000); - } - - /* We should never make it this far... */ - printk ("It is now safe to switch off your machine.\n"); - while(1); -} - -/* * Initialize VIA2 for Nubus access */ void __init via_nubus_init(void) { - nubus_active = 0; + /* don't set nubus_active = 0 here, it kills the Baboon */ + /* interrupt that we've already registered. */ /* unlock nubus transactions */ @@ -396,14 +377,22 @@ void __init via_nubus_init(void) /* set the line to be an output on non-RBV machines */ via2[vDirB] |= 0x02; } - via2[gBufB] |= 0x02; + + /* this seems to be an ADB bit on PMU machines */ + /* according to MkLinux. -- jmt */ + + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { + via2[gBufB] |= 0x02; + } /* disable nubus slot interrupts. */ if (rbv_present) { - via2[rSIER] = 0x7F; /* like VIA; bit 7=clr,set */ + via2[rSIER] = 0x7F; + via2[rSIER] = nubus_active | 0x80; } else { - via2[vBufA] = 0xFF; /* active low irqs, force high */ - via2[vDirA] = 0xFF; /* ddr to output. */ + via2[vBufA] = 0xFF; + via2[vDirA] = ~nubus_active; } } @@ -478,7 +467,7 @@ void via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) int irq_bit, i; unsigned char events; - if (!(events = ~via2[gBufA] & nubus_active)) return; + if (!(events = ~via2[gBufA] & nubus_active)) return; for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { if (events & irq_bit) { @@ -587,188 +576,3 @@ int via_irq_pending(int irq) } return 0; } - -void via_scsi_clear(void) -{ - volatile unsigned char deep_magic; - -#ifdef DEBUG_IRQUSE - printk("via_scsi_clear()\n"); -#endif - - /* We handle this in oss.c , but this gets called in mac_scsinew.c */ - if(oss_present) return; - - if (rbv_present) { - via2[rIFR] = (1<<3) | (1<<0) | rbv_clear; - deep_magic = via2[rBufB]; - } else { - deep_magic = via2[vBufB]; - } - mac_enable_irq(IRQ_MAC_SCSI); -} - -/* - * PRAM/RTC access routines - * - * Must be called with interrupts disabled and - * the RTC should be enabled. - */ - -static __u8 via_pram_readbyte(void) -{ - int i,reg; - __u8 data; - - reg = via1[vBufB] & ~VIA1B_vRTCClk; - - /* Set the RTC data line to be an input. */ - - via1[vDirB] &= ~VIA1B_vRTCData; - - /* The bits of the byte come out in MSB order */ - - data = 0; - for (i = 0 ; i < 8 ; i++) { - via1[vBufB] = reg; - via1[vBufB] = reg | VIA1B_vRTCClk; - data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData); - } - - /* Return RTC data line to output state */ - - via1[vDirB] |= VIA1B_vRTCData; - - return data; -} - -static void via_pram_writebyte(__u8 data) -{ - int i,reg,bit; - - reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData); - - /* The bits of the byte go in in MSB order */ - - for (i = 0 ; i < 8 ; i++) { - bit = data & 0x80? 1 : 0; - data <<= 1; - via1[vBufB] = reg | bit; - via1[vBufB] = reg | bit | VIA1B_vRTCClk; - } -} - -/* - * Execute a PRAM/RTC command. For read commands - * data should point to a one-byte buffer for the - * resulting data. For write commands it should point - * to the data byte to for the command. - * - * This function disables all interrupts while running. - */ - -void via_pram_command(int command, __u8 *data) -{ - unsigned long cpu_flags; - int is_read; - - save_flags(cpu_flags); - cli(); - - /* Enable the RTC and make sure the strobe line is high */ - - via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb; - - if (command & 0xFF00) { /* extended (two-byte) command */ - via_pram_writebyte((command & 0xFF00) >> 8); - via_pram_writebyte(command & 0xFF); - is_read = command & 0x8000; - } else { /* one-byte command */ - via_pram_writebyte(command); - is_read = command & 0x80; - } - if (is_read) { - *data = via_pram_readbyte(); - } else { - via_pram_writebyte(*data); - } - - /* All done, disable the RTC */ - - via1[vBufB] |= VIA1B_vRTCEnb; - - restore_flags(cpu_flags); -} - -/* - * Return the current time in seconds since January 1, 1904. - * - * This only works on machines with the VIA-based PRAM/RTC, which - * is basically any machine with Mac II-style ADB. - */ - -__u32 via_read_time(void) -{ - union { - __u8 cdata[4]; - __u32 idata; - } result, last_result; - int ct; - - /* - * The NetBSD guys say to loop until you get the same reading - * twice in a row. - */ - - ct = 0; - do { - if (++ct > 10) { - printk("via_read_time: couldn't get valid time, " - "last read = 0x%08X and 0x%08X\n", last_result.idata, - result.idata); - break; - } - - last_result.idata = result.idata; - result.idata = 0; - - via_pram_command(0x81, &result.cdata[3]); - via_pram_command(0x85, &result.cdata[2]); - via_pram_command(0x89, &result.cdata[1]); - via_pram_command(0x8D, &result.cdata[0]); - } while (result.idata != last_result.idata); - - return result.idata; -} - -/* - * Set the current time to a number of seconds since January 1, 1904. - * - * This only works on machines with the VIA-based PRAM/RTC, which - * is basically any machine with Mac II-style ADB. - */ - -void via_write_time(__u32 time) -{ - union { - __u8 cdata[4]; - __u32 idata; - } data; - __u8 temp; - - /* Clear the write protect bit */ - - temp = 0x55; - via_pram_command(0x35, &temp); - - data.idata = time; - via_pram_command(0x01, &data.cdata[3]); - via_pram_command(0x05, &data.cdata[2]); - via_pram_command(0x09, &data.cdata[1]); - via_pram_command(0x0D, &data.cdata[0]); - - /* Set the write protect bit */ - - temp = 0xD5; - via_pram_command(0x35, &temp); -} diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index 456520a64..146dc7279 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -207,7 +207,7 @@ void __init paging_init(void) { int chunk; unsigned long mem_avail = 0; - unsigned int zones_size[3] = { 0, }; + unsigned long zones_size[3] = { 0, }; #ifdef DEBUG { diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c index bd59fecba..8d6632d2f 100644 --- a/arch/m68k/mm/sun3mmu.c +++ b/arch/m68k/mm/sun3mmu.c @@ -30,7 +30,7 @@ extern void mmu_emu_init (void); -extern unsigned long free_area_init(unsigned long, unsigned long); +extern unsigned long free_area_init(unsigned long *zones_size); const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; diff --git a/arch/mips/config.in b/arch/mips/config.in index 91b4c6675..b6551a29e 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.40 2000/02/21 15:05:48 ralf Exp $ +# $Id: config.in,v 1.41 2000/02/23 00:41:00 ralf Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -64,12 +64,10 @@ comment 'CPU selection' if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then choice 'CPU core' \ "R3000 CONFIG_CPU_R3000 \ - R6000 CONFIG_CPU_R6000 \ R4300 CONFIG_CPU_R4300 \ R4x00 CONFIG_CPU_R4X00 \ R5000 CONFIG_CPU_R5000 \ R56x0 CONFIG_CPU_NEVADA \ - R8000 CONFIG_CPU_R8000 \ R10000 CONFIG_CPU_R10000" R4x00 bool ' ll/sc Instructions available' CONFIG_CPU_HAS_LLSC diff --git a/arch/mips/defconfig b/arch/mips/defconfig index 7b1bc7f4c..5516700c1 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -296,7 +296,7 @@ CONFIG_PSMOUSE=y # # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y @@ -315,20 +315,17 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems diff --git a/arch/mips/jazz/floppy-jazz.c b/arch/mips/jazz/floppy-jazz.c index 92c1f9506..76f39e52a 100644 --- a/arch/mips/jazz/floppy-jazz.c +++ b/arch/mips/jazz/floppy-jazz.c @@ -1,4 +1,4 @@ -/* $Id: floppy-jazz.c,v 1.1 1998/05/07 18:38:29 ralf Exp $ +/* $Id: floppy-jazz.c,v 1.2 1998/10/18 13:18:25 tsbogend Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -94,26 +94,11 @@ static unsigned long jazz_fd_getfdaddr1(void) return JAZZ_FDC_BASE; } -/* Pure 2^n version of get_order */ -extern inline int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long jazz_fd_dma_mem_alloc(unsigned long size) { - int order = __get_order(size); unsigned long mem; - mem = __get_dma_pages(GFP_KERNEL, order); + mem = __get_dma_pages(GFP_KERNEL, get_order(size)); if(!mem) return 0; vdma_alloc(PHYSADDR(mem), size); /* XXX error checking */ @@ -125,7 +110,7 @@ static void jazz_fd_dma_mem_free(unsigned long addr, unsigned long size) { vdma_free(vdma_phys2log(PHYSADDR(addr))); - free_pages(addr, __get_order(size)); + free_pages(addr, get_order(size)); } static unsigned long jazz_fd_drive_type(unsigned long n) diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 57e9bedfb..f1c65805f 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: mips_ksyms.c,v 1.23 2000/01/29 01:41:59 ralf Exp $ +/* $Id: mips_ksyms.c,v 1.24 2000/02/04 07:40:23 ralf Exp $ * * Export MIPS-specific functions needed for loadable modules. * @@ -55,7 +55,7 @@ EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL(clear_page); +EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); @@ -81,10 +81,10 @@ EXPORT_SYMBOL(csum_partial_copy); /* * Functions to control caches. */ -EXPORT_SYMBOL(flush_page_to_ram); -EXPORT_SYMBOL(flush_cache_all); -EXPORT_SYMBOL(dma_cache_wback_inv); -EXPORT_SYMBOL(dma_cache_inv); +EXPORT_SYMBOL(_flush_page_to_ram); +EXPORT_SYMBOL(_flush_cache_all); +EXPORT_SYMBOL(_dma_cache_wback_inv); +EXPORT_SYMBOL(_dma_cache_inv); EXPORT_SYMBOL(invalid_pte_table); diff --git a/arch/mips/lib/floppy-std.c b/arch/mips/lib/floppy-std.c index 3d1c95feb..ada280d55 100644 --- a/arch/mips/lib/floppy-std.c +++ b/arch/mips/lib/floppy-std.c @@ -1,4 +1,4 @@ -/* $Id: floppy-std.c,v 1.3 1998/10/28 12:38:13 ralf Exp $ +/* $Id: floppy-std.c,v 1.2 1999/01/04 16:03:51 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -102,33 +102,18 @@ static unsigned long std_fd_getfdaddr1(void) return 0x3f0; } -/* Pure 2^n version of get_order */ -static int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - static unsigned long std_fd_dma_mem_alloc(unsigned long size) { - int order = __get_order(size); unsigned long mem; - mem = __get_dma_pages(GFP_KERNEL,order); + mem = __get_dma_pages(GFP_KERNEL,get_order(size)); return mem; } static void std_fd_dma_mem_free(unsigned long addr, unsigned long size) { - free_pages(addr, __get_order(size)); + free_pages(addr, get_order(size)); } static unsigned long std_fd_drive_type(unsigned long n) diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index f0d34b0d6..d8929b93c 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -30,10 +30,6 @@ ifdef CONFIG_CPU_NEVADA O_OBJS += r4xx0.o endif -ifdef CONFIG_CPU_R6000 -O_OBJS += r6000.o -endif - ifdef CONFIG_SGI_IP22 O_OBJS += umap.o endif diff --git a/arch/mips/mm/andes.c b/arch/mips/mm/andes.c index ab1715be3..d76b5f141 100644 --- a/arch/mips/mm/andes.c +++ b/arch/mips/mm/andes.c @@ -1,4 +1,4 @@ -/* $Id: andes.c,v 1.9 2000/01/27 01:05:23 ralf Exp $ +/* $Id: andes.c,v 1.10 2000/02/13 20:52:05 harald Exp $ * * andes.c: MMU and cache operations for the R10000 (ANDES). * @@ -163,15 +163,15 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, void __init ld_mmu_andes(void) { - clear_page = andes_clear_page; - copy_page = andes_copy_page; + _clear_page = andes_clear_page; + _copy_page = andes_copy_page; - flush_cache_all = andes_flush_cache_all; - flush_cache_mm = andes_flush_cache_mm; - flush_cache_range = andes_flush_cache_range; - flush_cache_page = andes_flush_cache_page; - flush_cache_sigtramp = andes_flush_cache_sigtramp; - flush_page_to_ram = andes_flush_page_to_ram; + _flush_cache_all = andes_flush_cache_all; + _flush_cache_mm = andes_flush_cache_mm; + _flush_cache_range = andes_flush_cache_range; + _flush_cache_page = andes_flush_cache_page; + _flush_cache_sigtramp = andes_flush_cache_sigtramp; + _flush_page_to_ram = andes_flush_page_to_ram; flush_cache_all(); flush_tlb_all(); diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c index cf4816889..afbbef5eb 100644 --- a/arch/mips/mm/loadmmu.c +++ b/arch/mips/mm/loadmmu.c @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: loadmmu.c,v 1.13 1999/10/09 00:00:58 ralf Exp $ + * $Id: loadmmu.c,v 1.14 2000/01/27 01:05:23 ralf Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -17,22 +17,22 @@ #include <asm/sgialib.h> /* memory functions */ -void (*clear_page)(void * page); -void (*copy_page)(void * to, void * from); +void (*_clear_page)(void * page); +void (*_copy_page)(void * to, void * from); /* Cache operations. */ -void (*flush_cache_all)(void); -void (*flush_cache_mm)(struct mm_struct *mm); -void (*flush_cache_range)(struct mm_struct *mm, unsigned long start, +void (*_flush_cache_all)(void); +void (*_flush_cache_mm)(struct mm_struct *mm); +void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, unsigned long end); -void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page); -void (*flush_cache_sigtramp)(unsigned long addr); -void (*flush_page_to_ram)(struct page * page); +void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); +void (*_flush_cache_sigtramp)(unsigned long addr); +void (*_flush_page_to_ram)(struct page * page); /* DMA cache operations. */ -void (*dma_cache_wback_inv)(unsigned long start, unsigned long size); -void (*dma_cache_wback)(unsigned long start, unsigned long size); -void (*dma_cache_inv)(unsigned long start, unsigned long size); +void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); +void (*_dma_cache_wback)(unsigned long start, unsigned long size); +void (*_dma_cache_inv)(unsigned long start, unsigned long size); #ifdef CONFIG_CPU_R3000 extern void ld_mmu_r2300(void); @@ -85,21 +85,6 @@ void __init loadmmu(void) break; #endif -#ifdef CONFIG_CPU_R6000 - case CPU_R6000: - case CPU_R6000A: - printk("Loading R6000 MMU routines.\n"); - ld_mmu_r6000(); - break; -#endif - -#ifdef CONFIG_CPU_R8000 - case CPU_R8000: - printk("Loading TFP MMU routines.\n"); - ld_mmu_tfp(); - break; -#endif - #ifdef CONFIG_CPU_R10000 case CPU_R10000: printk("Loading R10000 MMU routines.\n"); diff --git a/arch/mips/mm/r2300.c b/arch/mips/mm/r2300.c index 6c7126425..63d9b1f7b 100644 --- a/arch/mips/mm/r2300.c +++ b/arch/mips/mm/r2300.c @@ -7,7 +7,7 @@ * Copyright (C) 1998, 2000 Harald Koerfgen * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov * - * $Id: r2300.c,v 1.13 2000/01/27 01:05:23 ralf Exp $ + * $Id: r2300.c,v 1.14 2000/02/13 20:52:05 harald Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -636,20 +636,20 @@ void __init ld_mmu_r2300(void) { printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - clear_page = r3k_clear_page; - copy_page = r3k_copy_page; + _clear_page = r3k_clear_page; + _copy_page = r3k_copy_page; probe_icache(); probe_dcache(); - flush_cache_all = r3k_flush_cache_all; - flush_cache_mm = r3k_flush_cache_mm; - flush_cache_range = r3k_flush_cache_range; - flush_cache_page = r3k_flush_cache_page; - flush_cache_sigtramp = r3k_flush_cache_sigtramp; - flush_page_to_ram = r3k_flush_page_to_ram; + _flush_cache_all = r3k_flush_cache_all; + _flush_cache_mm = r3k_flush_cache_mm; + _flush_cache_range = r3k_flush_cache_range; + _flush_cache_page = r3k_flush_cache_page; + _flush_cache_sigtramp = r3k_flush_cache_sigtramp; + _flush_page_to_ram = r3k_flush_page_to_ram; - dma_cache_wback_inv = r3k_dma_cache_wback_inv; + _dma_cache_wback_inv = r3k_dma_cache_wback_inv; flush_tlb_all(); } diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c index 2896ddea9..bb377fb16 100644 --- a/arch/mips/mm/r4xx0.c +++ b/arch/mips/mm/r4xx0.c @@ -1,4 +1,4 @@ -/* $Id: r4xx0.c,v 1.27 2000/01/27 01:05:23 ralf Exp $ +/* $Id: r4xx0.c,v 1.28 2000/02/13 20:52:05 harald Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -2636,36 +2636,36 @@ static void __init setup_noscache_funcs(void) switch(dc_lsize) { case 16: - clear_page = r4k_clear_page_d16; - copy_page = r4k_copy_page_d16; - flush_cache_all = r4k_flush_cache_all_d16i16; - flush_cache_mm = r4k_flush_cache_mm_d16i16; - flush_cache_range = r4k_flush_cache_range_d16i16; - flush_cache_page = r4k_flush_cache_page_d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_d16i16; + _clear_page = r4k_clear_page_d16; + _copy_page = r4k_copy_page_d16; + _flush_cache_all = r4k_flush_cache_all_d16i16; + _flush_cache_mm = r4k_flush_cache_mm_d16i16; + _flush_cache_range = r4k_flush_cache_range_d16i16; + _flush_cache_page = r4k_flush_cache_page_d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_d16i16; break; case 32: prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0; if (prid == 0x2010) { /* R4600 V1.7 */ - clear_page = r4k_clear_page_r4600_v1; - copy_page = r4k_copy_page_r4600_v1; + _clear_page = r4k_clear_page_r4600_v1; + _copy_page = r4k_copy_page_r4600_v1; } else if (prid == 0x2020) { /* R4600 V2.0 */ - clear_page = r4k_clear_page_r4600_v2; - copy_page = r4k_copy_page_r4600_v2; + _clear_page = r4k_clear_page_r4600_v2; + _copy_page = r4k_copy_page_r4600_v2; } else { - clear_page = r4k_clear_page_d32; - copy_page = r4k_copy_page_d32; + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; } - flush_cache_all = r4k_flush_cache_all_d32i32; - flush_cache_mm = r4k_flush_cache_mm_d32i32; - flush_cache_range = r4k_flush_cache_range_d32i32; - flush_cache_page = r4k_flush_cache_page_d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_d32i32; + _flush_cache_all = r4k_flush_cache_all_d32i32; + _flush_cache_mm = r4k_flush_cache_mm_d32i32; + _flush_cache_range = r4k_flush_cache_range_d32i32; + _flush_cache_page = r4k_flush_cache_page_d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32i32; break; } - dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; - dma_cache_wback = r4k_dma_cache_wback; - dma_cache_inv = r4k_dma_cache_inv_pc; + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv_pc; } static void __init setup_scache_funcs(void) @@ -2674,82 +2674,82 @@ static void __init setup_scache_funcs(void) case 16: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s16d16i16; - flush_cache_mm = r4k_flush_cache_mm_s16d16i16; - flush_cache_range = r4k_flush_cache_range_s16d16i16; - flush_cache_page = r4k_flush_cache_page_s16d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; + _flush_cache_all = r4k_flush_cache_all_s16d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s16d16i16; + _flush_cache_range = r4k_flush_cache_range_s16d16i16; + _flush_cache_page = r4k_flush_cache_page_s16d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; break; case 32: panic("Invalid cache configuration detected"); }; - clear_page = r4k_clear_page_s16; - copy_page = r4k_copy_page_s16; + _clear_page = r4k_clear_page_s16; + _copy_page = r4k_copy_page_s16; break; case 32: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s32d16i16; - flush_cache_mm = r4k_flush_cache_mm_s32d16i16; - flush_cache_range = r4k_flush_cache_range_s32d16i16; - flush_cache_page = r4k_flush_cache_page_s32d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; + _flush_cache_all = r4k_flush_cache_all_s32d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s32d16i16; + _flush_cache_range = r4k_flush_cache_range_s32d16i16; + _flush_cache_page = r4k_flush_cache_page_s32d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s32d32i32; - flush_cache_mm = r4k_flush_cache_mm_s32d32i32; - flush_cache_range = r4k_flush_cache_range_s32d32i32; - flush_cache_page = r4k_flush_cache_page_s32d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; + _flush_cache_all = r4k_flush_cache_all_s32d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; + _flush_cache_range = r4k_flush_cache_range_s32d32i32; + _flush_cache_page = r4k_flush_cache_page_s32d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; break; }; - clear_page = r4k_clear_page_s32; - copy_page = r4k_copy_page_s32; + _clear_page = r4k_clear_page_s32; + _copy_page = r4k_copy_page_s32; break; case 64: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s64d16i16; - flush_cache_mm = r4k_flush_cache_mm_s64d16i16; - flush_cache_range = r4k_flush_cache_range_s64d16i16; - flush_cache_page = r4k_flush_cache_page_s64d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; + _flush_cache_all = r4k_flush_cache_all_s64d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s64d16i16; + _flush_cache_range = r4k_flush_cache_range_s64d16i16; + _flush_cache_page = r4k_flush_cache_page_s64d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s64d32i32; - flush_cache_mm = r4k_flush_cache_mm_s64d32i32; - flush_cache_range = r4k_flush_cache_range_s64d32i32; - flush_cache_page = r4k_flush_cache_page_s64d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; + _flush_cache_all = r4k_flush_cache_all_s64d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; + _flush_cache_range = r4k_flush_cache_range_s64d32i32; + _flush_cache_page = r4k_flush_cache_page_s64d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; break; }; - clear_page = r4k_clear_page_s64; - copy_page = r4k_copy_page_s64; + _clear_page = r4k_clear_page_s64; + _copy_page = r4k_copy_page_s64; break; case 128: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s128d16i16; - flush_cache_mm = r4k_flush_cache_mm_s128d16i16; - flush_cache_range = r4k_flush_cache_range_s128d16i16; - flush_cache_page = r4k_flush_cache_page_s128d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; + _flush_cache_all = r4k_flush_cache_all_s128d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s128d16i16; + _flush_cache_range = r4k_flush_cache_range_s128d16i16; + _flush_cache_page = r4k_flush_cache_page_s128d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s128d32i32; - flush_cache_mm = r4k_flush_cache_mm_s128d32i32; - flush_cache_range = r4k_flush_cache_range_s128d32i32; - flush_cache_page = r4k_flush_cache_page_s128d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; + _flush_cache_all = r4k_flush_cache_all_s128d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; + _flush_cache_range = r4k_flush_cache_range_s128d32i32; + _flush_cache_page = r4k_flush_cache_page_s128d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; break; }; - clear_page = r4k_clear_page_s128; - copy_page = r4k_copy_page_s128; + _clear_page = r4k_clear_page_s128; + _copy_page = r4k_copy_page_s128; break; } - dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; - dma_cache_wback = r4k_dma_cache_wback; - dma_cache_inv = r4k_dma_cache_inv_sc; + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv_sc; } typedef int (*probe_func_t)(unsigned long); @@ -2788,12 +2788,12 @@ void __init ld_mmu_r4xx0(void) case CPU_R4700: case CPU_R5000: case CPU_NEVADA: - flush_cache_page = r4k_flush_cache_page_d32i32_r4600; + _flush_cache_page = r4k_flush_cache_page_d32i32_r4600; } flush_cache_sigtramp = r4k_flush_cache_sigtramp; if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { - flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; + _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; } flush_cache_all(); diff --git a/arch/mips/mm/r6000.c b/arch/mips/mm/r6000.c deleted file mode 100644 index 364901d4d..000000000 --- a/arch/mips/mm/r6000.c +++ /dev/null @@ -1,250 +0,0 @@ -/* $Id: r6000.c,v 1.9 2000/01/27 01:05:23 ralf Exp $ - * - * r6000.c: MMU and cache routines for the R6000 processors. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include <asm/cacheops.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/sgialib.h> -#include <asm/mmu_context.h> - -__asm__(".set mips2"); /* because we know... */ - -/* page functions */ -void r6000_clear_page(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "addiu\t$1,%0,%2\n" - "1:\tsw\t$0,(%0)\n\t" - "sw\t$0,4(%0)\n\t" - "sw\t$0,8(%0)\n\t" - "sw\t$0,12(%0)\n\t" - "addiu\t%0,32\n\t" - "sw\t$0,-16(%0)\n\t" - "sw\t$0,-12(%0)\n\t" - "sw\t$0,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t$0,-4(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), - "I" (PAGE_SIZE) - :"$1","memory"); -} - -static void r6000_copy_page(void * to, void * from) -{ - unsigned long dummy1, dummy2; - unsigned long reg1, reg2, reg3, reg4; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "addiu\t$1,%0,%8\n" - "1:\tlw\t%2,(%1)\n\t" - "lw\t%3,4(%1)\n\t" - "lw\t%4,8(%1)\n\t" - "lw\t%5,12(%1)\n\t" - "sw\t%2,(%0)\n\t" - "sw\t%3,4(%0)\n\t" - "sw\t%4,8(%0)\n\t" - "sw\t%5,12(%0)\n\t" - "lw\t%2,16(%1)\n\t" - "lw\t%3,20(%1)\n\t" - "lw\t%4,24(%1)\n\t" - "lw\t%5,28(%1)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%3,20(%0)\n\t" - "sw\t%4,24(%0)\n\t" - "sw\t%5,28(%0)\n\t" - "addiu\t%0,64\n\t" - "addiu\t%1,64\n\t" - "lw\t%2,-32(%1)\n\t" - "lw\t%3,-28(%1)\n\t" - "lw\t%4,-24(%1)\n\t" - "lw\t%5,-20(%1)\n\t" - "sw\t%2,-32(%0)\n\t" - "sw\t%3,-28(%0)\n\t" - "sw\t%4,-24(%0)\n\t" - "sw\t%5,-20(%0)\n\t" - "lw\t%2,-16(%1)\n\t" - "lw\t%3,-12(%1)\n\t" - "lw\t%4,-8(%1)\n\t" - "lw\t%5,-4(%1)\n\t" - "sw\t%2,-16(%0)\n\t" - "sw\t%3,-12(%0)\n\t" - "sw\t%4,-8(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sw\t%5,-4(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), - "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) - :"0" (to), "1" (from), - "I" (PAGE_SIZE)); -} - -/* Cache operations. XXX Write these dave... */ -static inline void r6000_flush_cache_all(void) -{ - /* XXX */ -} - -static void r6000_flush_cache_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void r6000_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void r6000_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - /* XXX */ -} - -static void r6000_flush_page_to_ram(struct page * page) -{ - /* XXX */ -} - -static void r6000_flush_cache_sigtramp(unsigned long page) -{ - /* XXX */ -} - -/* TLB operations. XXX Write these dave... */ -void flush_tlb_all(void) -{ - /* XXX */ -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - /* XXX */ -} - -void load_pgd(unsigned long pg_dir) -{ -} - -void pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - - /* - * The plain and boring version for the R3000. No cache flushing - * stuff is implemented since the R3000 has physical caches. - */ - __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\tsw\t%2,(%0)\n\t" - "sw\t%2,4(%0)\n\t" - "sw\t%2,8(%0)\n\t" - "sw\t%2,12(%0)\n\t" - "sw\t%2,16(%0)\n\t" - "sw\t%2,20(%0)\n\t" - "sw\t%2,24(%0)\n\t" - "sw\t%2,28(%0)\n\t" - "subu\t%1,1\n\t" - "bnez\t%1,1b\n\t" - "addiu\t%0,32\n\t" - ".set\treorder" - :"=r" (dummy1), - "=r" (dummy2) - :"r" ((unsigned long) invalid_pte_table), - "0" (page), - "1" (PAGE_SIZE/(sizeof(pmd_t)*8))); -} - -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - r6000_flush_tlb_page(vma, address); - /* - * FIXME: We should also reload a new entry into the TLB to - * avoid unnecessary exceptions. - */ -} - -void show_regs(struct pt_regs * regs) -{ - /* - * Saved main processor registers - */ - printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - 0, (unsigned long) regs->regs[1], (unsigned long) regs->regs[2], - (unsigned long) regs->regs[3], (unsigned long) regs->regs[4], - (unsigned long) regs->regs[5], (unsigned long) regs->regs[6], - (unsigned long) regs->regs[7]); - printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[8], (unsigned long) regs->regs[9], - (unsigned long) regs->regs[10], (unsigned long) regs->regs[11], - (unsigned long) regs->regs[12], (unsigned long) regs->regs[13], - (unsigned long) regs->regs[14], (unsigned long) regs->regs[15]); - printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[16], (unsigned long) regs->regs[17], - (unsigned long) regs->regs[18], (unsigned long) regs->regs[19], - (unsigned long) regs->regs[20], (unsigned long) regs->regs[21], - (unsigned long) regs->regs[22], (unsigned long) regs->regs[23]); - printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n", - (unsigned long) regs->regs[24], (unsigned long) regs->regs[25], - (unsigned long) regs->regs[28], (unsigned long) regs->regs[29], - (unsigned long) regs->regs[30], (unsigned long) regs->regs[31]); - - /* - * Saved cp0 registers - */ - printk("epc : %08lx\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - /* XXX */ -} - -void __init ld_mmu_r6000(void) -{ - clear_page = r6000_clear_page; - copy_page = r6000_copy_page; - - flush_cache_all = r6000_flush_cache_all; - flush_cache_mm = r6000_flush_cache_mm; - flush_cache_range = r6000_flush_cache_range; - flush_cache_page = r6000_flush_cache_page; - flush_cache_sigtramp = r6000_flush_cache_sigtramp; - flush_page_to_ram = r6000_flush_page_to_ram; - - flush_cache_all(); - flush_tlb_all(); -} diff --git a/arch/mips/mm/tfp.c b/arch/mips/mm/tfp.c deleted file mode 100644 index 2aa0e91a5..000000000 --- a/arch/mips/mm/tfp.c +++ /dev/null @@ -1,102 +0,0 @@ -/* $Id: tfp.c,v 1.9 2000/01/27 01:05:23 ralf Exp $ - * - * tfp.c: MMU and cache routines specific to the r8000 (TFP). - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/sgialib.h> -#include <asm/mmu_context.h> - -extern unsigned long mips_tlb_entries; - -/* Cache operations. XXX Write these dave... */ -static inline void tfp_flush_cache_all(void) -{ - /* XXX */ -} - -static void tfp_flush_cache_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void tfp_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void tfp_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - /* XXX */ -} - -static void tfp_flush_page_to_ram(struct page * page) -{ - /* XXX */ -} - -static void tfp_flush_cache_sigtramp(unsigned long page) -{ - /* XXX */ -} - -/* TLB operations. XXX Write these dave... */ -void flush_tlb_all(void) -{ - /* XXX */ -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - /* XXX */ -} - -void load_pgd(unsigned long pg_dir) -{ -} - -void pgd_init(unsigned long page) -{ -} - -void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - /* XXX */ -} - -void __init ld_mmu_tfp(void) -{ - flush_cache_all = tfp_flush_cache_all; - flush_cache_mm = tfp_flush_cache_mm; - flush_cache_range = tfp_flush_cache_range; - flush_cache_page = tfp_flush_cache_page; - flush_cache_sigtramp = tfp_flush_cache_sigtramp; - flush_page_to_ram = tfp_flush_page_to_ram; - - flush_cache_all(); - flush_tlb_all(); -} diff --git a/arch/mips/sni/dma.c b/arch/mips/sni/dma.c index 26a7c0f0b..2f092abf4 100644 --- a/arch/mips/sni/dma.c +++ b/arch/mips/sni/dma.c @@ -1,4 +1,4 @@ -/* $Id: dma.c,v 1.1 2000/02/16 21:21:58 ralf Exp $ +/* $Id: dma.c,v 1.1 2000/02/18 00:24:30 ralf Exp $ * * Dynamic DMA mapping support. * @@ -16,26 +16,12 @@ #include <linux/pci.h> #include <asm/io.h> -/* Pure 2^n version of get_order */ -extern __inline__ int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { void *ret; int gfp = GFP_ATOMIC; - int order = __get_order(size); + int order = get_order(size); if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; @@ -52,5 +38,5 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, __get_order(size)); + free_pages((unsigned long)vaddr, get_order(size)); } diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index 1d8f9c8f6..9c6687735 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -246,7 +246,7 @@ CONFIG_VT_CONSOLE=y # CONFIG_USB is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set @@ -265,20 +265,17 @@ CONFIG_VT_CONSOLE=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems @@ -287,7 +284,6 @@ CONFIG_EXT2_FS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set -# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set diff --git a/arch/mips64/kernel/mips64_ksyms.c b/arch/mips64/kernel/mips64_ksyms.c index 4fc755e39..eb1317ca3 100644 --- a/arch/mips64/kernel/mips64_ksyms.c +++ b/arch/mips64/kernel/mips64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: mips64_ksyms.c,v 1.6 2000/01/29 01:41:59 ralf Exp $ +/* $Id: mips64_ksyms.c,v 1.7 2000/02/04 07:40:24 ralf Exp $ * * Export MIPS64-specific functions needed for loadable modules. * @@ -55,7 +55,7 @@ EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL(clear_page); +EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); @@ -81,10 +81,10 @@ EXPORT_SYMBOL(csum_partial_copy); /* * Functions to control caches. */ -EXPORT_SYMBOL(flush_page_to_ram); -EXPORT_SYMBOL(flush_cache_all); -EXPORT_SYMBOL(dma_cache_wback_inv); -EXPORT_SYMBOL(dma_cache_inv); +EXPORT_SYMBOL(_flush_page_to_ram); +EXPORT_SYMBOL(_flush_cache_all); +EXPORT_SYMBOL(_dma_cache_wback_inv); +EXPORT_SYMBOL(_dma_cache_inv); EXPORT_SYMBOL(invalid_pte_table); diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c index 825562342..5fe51a31c 100644 --- a/arch/mips64/kernel/traps.c +++ b/arch/mips64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.10 1999/11/23 17:12:49 ralf Exp $ +/* $Id: traps.c,v 1.4 2000/01/20 23:50:27 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -22,6 +22,7 @@ #include <asm/pgtable.h> #include <asm/io.h> #include <asm/bootinfo.h> +#include <asm/ptrace.h> #include <asm/watch.h> #include <asm/system.h> #include <asm/uaccess.h> diff --git a/arch/mips64/mm/Makefile b/arch/mips64/mm/Makefile index db898cad4..fe95aff18 100644 --- a/arch/mips64/mm/Makefile +++ b/arch/mips64/mm/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 1999/12/04 03:59:00 ralf Exp $ +# $Id: Makefile,v 1.4 2000/01/17 23:32:46 ralf Exp $ # # Makefile for the Linux/MIPS-specific parts of the memory manager. # @@ -18,9 +18,6 @@ endif ifdef CONFIG_CPU_NEVADA O_OBJS += r4xx0.o endif -ifdef CONFIG_CPU_R8000 -O_OBJS += tfp.o -endif ifdef CONFIG_CPU_R10000 O_OBJS += andes.o endif diff --git a/arch/mips64/mm/andes.c b/arch/mips64/mm/andes.c index 895e5db4a..401e07472 100644 --- a/arch/mips64/mm/andes.c +++ b/arch/mips64/mm/andes.c @@ -1,4 +1,4 @@ -/* $Id: andes.c,v 1.4 2000/01/17 23:32:46 ralf Exp $ +/* $Id: andes.c,v 1.5 2000/01/27 01:05:24 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -436,25 +436,25 @@ void __init ld_mmu_andes(void) printk("Secondary cache sized at %ldK, linesize %ld\n", scache_size() >> 10, sc_lsize()); - clear_page = andes_clear_page; - copy_page = andes_copy_page; + _clear_page = andes_clear_page; + _copy_page = andes_copy_page; - flush_cache_all = andes_flush_cache_all; - flush_cache_mm = andes_flush_cache_mm; - flush_cache_range = andes_flush_cache_range; - flush_cache_page = andes_flush_cache_page; - flush_cache_sigtramp = andes_flush_cache_sigtramp; - flush_page_to_ram = andes_flush_page_to_ram; + _flush_cache_all = andes_flush_cache_all; + _flush_cache_mm = andes_flush_cache_mm; + _flush_cache_range = andes_flush_cache_range; + _flush_cache_page = andes_flush_cache_page; + _flush_cache_sigtramp = andes_flush_cache_sigtramp; + _flush_page_to_ram = andes_flush_page_to_ram; - flush_tlb_all = andes_flush_tlb_all; - flush_tlb_mm = andes_flush_tlb_mm; - flush_tlb_range = andes_flush_tlb_range; - flush_tlb_page = andes_flush_tlb_page; + _flush_tlb_all = andes_flush_tlb_all; + _flush_tlb_mm = andes_flush_tlb_mm; + _flush_tlb_range = andes_flush_tlb_range; + _flush_tlb_page = andes_flush_tlb_page; update_mmu_cache = andes_update_mmu_cache; - show_regs = andes_show_regs; - user_mode = andes_user_mode; + _show_regs = andes_show_regs; + _user_mode = andes_user_mode; flush_cache_all(); write_32bit_cp0_register(CP0_WIRED, 0); diff --git a/arch/mips64/mm/loadmmu.c b/arch/mips64/mm/loadmmu.c index b2dd9e11e..69f661c0b 100644 --- a/arch/mips64/mm/loadmmu.c +++ b/arch/mips64/mm/loadmmu.c @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.4 2000/01/17 23:32:46 ralf Exp $ +/* $Id: loadmmu.c,v 1.5 2000/01/27 01:05:24 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -21,40 +21,39 @@ #include <asm/sgialib.h> /* memory functions */ -void (*clear_page)(void * page); -void (*copy_page)(void * to, void * from); +void (*_clear_page)(void * page); +void (*_copy_page)(void * to, void * from); /* Cache operations. */ -void (*flush_cache_all)(void); -void (*flush_cache_mm)(struct mm_struct *mm); -void (*flush_cache_range)(struct mm_struct *mm, unsigned long start, - unsigned long end); -void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page); -void (*flush_cache_sigtramp)(unsigned long addr); -void (*flush_page_to_ram)(struct page * page); +void (*_flush_cache_all)(void); +void (*_flush_cache_mm)(struct mm_struct *mm); +void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, + unsigned long end); +void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); +void (*_flush_cache_sigtramp)(unsigned long addr); +void (*_flush_page_to_ram)(struct page * page); /* DMA cache operations. */ -void (*dma_cache_wback_inv)(unsigned long start, unsigned long size); -void (*dma_cache_wback)(unsigned long start, unsigned long size); -void (*dma_cache_inv)(unsigned long start, unsigned long size); +void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); +void (*_dma_cache_wback)(unsigned long start, unsigned long size); +void (*_dma_cache_inv)(unsigned long start, unsigned long size); /* TLB operations. */ -void (*flush_tlb_all)(void); -void (*flush_tlb_mm)(struct mm_struct *mm); -void (*flush_tlb_range)(struct mm_struct *mm, unsigned long start, +void (*_flush_tlb_all)(void); +void (*_flush_tlb_mm)(struct mm_struct *mm); +void (*_flush_tlb_range)(struct mm_struct *mm, unsigned long start, unsigned long end); -void (*flush_tlb_page)(struct vm_area_struct *vma, unsigned long page); +void (*_flush_tlb_page)(struct vm_area_struct *vma, unsigned long page); /* Miscellaneous. */ void (*update_mmu_cache)(struct vm_area_struct * vma, unsigned long address, pte_t pte); -void (*show_regs)(struct pt_regs *); +void (*_show_regs)(struct pt_regs *); -int (*user_mode)(struct pt_regs *); +int (*_user_mode)(struct pt_regs *); extern void ld_mmu_r4xx0(void); -extern void ld_mmu_tfp(void); extern void ld_mmu_andes(void); void __init load_mmu(void) @@ -84,13 +83,6 @@ void __init load_mmu(void) break; #endif -#if defined (CONFIG_CPU_R8000) - case CPU_R8000: - printk("Loading TFP MMU routines.\n"); - ld_mmu_tfp(); - break; -#endif - #if defined (CONFIG_CPU_R10000) case CPU_R10000: printk("Loading R10000 MMU routines.\n"); diff --git a/arch/mips64/mm/r4xx0.c b/arch/mips64/mm/r4xx0.c index 4c85d6ba1..e8f19d4a5 100644 --- a/arch/mips64/mm/r4xx0.c +++ b/arch/mips64/mm/r4xx0.c @@ -1,4 +1,4 @@ -/* $Id: r4xx0.c,v 1.6 2000/01/17 23:32:46 ralf Exp $ +/* $Id: r4xx0.c,v 1.7 2000/01/27 01:05:24 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -2352,36 +2352,36 @@ static void __init setup_noscache_funcs(void) switch(dc_lsize) { case 16: - clear_page = r4k_clear_page_d16; - copy_page = r4k_copy_page_d16; - flush_cache_all = r4k_flush_cache_all_d16i16; - flush_cache_mm = r4k_flush_cache_mm_d16i16; - flush_cache_range = r4k_flush_cache_range_d16i16; - flush_cache_page = r4k_flush_cache_page_d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_d16i16; + _clear_page = r4k_clear_page_d16; + _copy_page = r4k_copy_page_d16; + _flush_cache_all = r4k_flush_cache_all_d16i16; + _flush_cache_mm = r4k_flush_cache_mm_d16i16; + _flush_cache_range = r4k_flush_cache_range_d16i16; + _flush_cache_page = r4k_flush_cache_page_d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_d16i16; break; case 32: prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0; if (prid == 0x2010) { /* R4600 V1.7 */ - clear_page = r4k_clear_page_r4600_v1; - copy_page = r4k_copy_page_r4600_v1; + _clear_page = r4k_clear_page_r4600_v1; + _copy_page = r4k_copy_page_r4600_v1; } else if (prid == 0x2020) { /* R4600 V2.0 */ - clear_page = r4k_clear_page_r4600_v2; - copy_page = r4k_copy_page_r4600_v2; + _clear_page = r4k_clear_page_r4600_v2; + _copy_page = r4k_copy_page_r4600_v2; } else { - clear_page = r4k_clear_page_d32; - copy_page = r4k_copy_page_d32; + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; } - flush_cache_all = r4k_flush_cache_all_d32i32; - flush_cache_mm = r4k_flush_cache_mm_d32i32; - flush_cache_range = r4k_flush_cache_range_d32i32; - flush_cache_page = r4k_flush_cache_page_d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_d32i32; + _flush_cache_all = r4k_flush_cache_all_d32i32; + _flush_cache_mm = r4k_flush_cache_mm_d32i32; + _flush_cache_range = r4k_flush_cache_range_d32i32; + _flush_cache_page = r4k_flush_cache_page_d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32i32; break; } - dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; - dma_cache_wback = r4k_dma_cache_wback; - dma_cache_inv = r4k_dma_cache_inv_pc; + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv_pc; } static void __init setup_scache_funcs(void) @@ -2390,82 +2390,82 @@ static void __init setup_scache_funcs(void) case 16: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s16d16i16; - flush_cache_mm = r4k_flush_cache_mm_s16d16i16; - flush_cache_range = r4k_flush_cache_range_s16d16i16; - flush_cache_page = r4k_flush_cache_page_s16d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; + _flush_cache_all = r4k_flush_cache_all_s16d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s16d16i16; + _flush_cache_range = r4k_flush_cache_range_s16d16i16; + _flush_cache_page = r4k_flush_cache_page_s16d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; break; case 32: panic("Invalid cache configuration detected"); }; - clear_page = r4k_clear_page_s16; - copy_page = r4k_copy_page_s16; + _clear_page = r4k_clear_page_s16; + _copy_page = r4k_copy_page_s16; break; case 32: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s32d16i16; - flush_cache_mm = r4k_flush_cache_mm_s32d16i16; - flush_cache_range = r4k_flush_cache_range_s32d16i16; - flush_cache_page = r4k_flush_cache_page_s32d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; + _flush_cache_all = r4k_flush_cache_all_s32d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s32d16i16; + _flush_cache_range = r4k_flush_cache_range_s32d16i16; + _flush_cache_page = r4k_flush_cache_page_s32d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s32d32i32; - flush_cache_mm = r4k_flush_cache_mm_s32d32i32; - flush_cache_range = r4k_flush_cache_range_s32d32i32; - flush_cache_page = r4k_flush_cache_page_s32d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; + _flush_cache_all = r4k_flush_cache_all_s32d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; + _flush_cache_range = r4k_flush_cache_range_s32d32i32; + _flush_cache_page = r4k_flush_cache_page_s32d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; break; }; - clear_page = r4k_clear_page_s32; - copy_page = r4k_copy_page_s32; + _clear_page = r4k_clear_page_s32; + _copy_page = r4k_copy_page_s32; break; case 64: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s64d16i16; - flush_cache_mm = r4k_flush_cache_mm_s64d16i16; - flush_cache_range = r4k_flush_cache_range_s64d16i16; - flush_cache_page = r4k_flush_cache_page_s64d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; + _flush_cache_all = r4k_flush_cache_all_s64d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s64d16i16; + _flush_cache_range = r4k_flush_cache_range_s64d16i16; + _flush_cache_page = r4k_flush_cache_page_s64d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s64d32i32; - flush_cache_mm = r4k_flush_cache_mm_s64d32i32; - flush_cache_range = r4k_flush_cache_range_s64d32i32; - flush_cache_page = r4k_flush_cache_page_s64d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; + _flush_cache_all = r4k_flush_cache_all_s64d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; + _flush_cache_range = r4k_flush_cache_range_s64d32i32; + _flush_cache_page = r4k_flush_cache_page_s64d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; break; }; - clear_page = r4k_clear_page_s64; - copy_page = r4k_copy_page_s64; + _clear_page = r4k_clear_page_s64; + _copy_page = r4k_copy_page_s64; break; case 128: switch(dc_lsize) { case 16: - flush_cache_all = r4k_flush_cache_all_s128d16i16; - flush_cache_mm = r4k_flush_cache_mm_s128d16i16; - flush_cache_range = r4k_flush_cache_range_s128d16i16; - flush_cache_page = r4k_flush_cache_page_s128d16i16; - flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; + _flush_cache_all = r4k_flush_cache_all_s128d16i16; + _flush_cache_mm = r4k_flush_cache_mm_s128d16i16; + _flush_cache_range = r4k_flush_cache_range_s128d16i16; + _flush_cache_page = r4k_flush_cache_page_s128d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s128d32i32; - flush_cache_mm = r4k_flush_cache_mm_s128d32i32; - flush_cache_range = r4k_flush_cache_range_s128d32i32; - flush_cache_page = r4k_flush_cache_page_s128d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; + _flush_cache_all = r4k_flush_cache_all_s128d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; + _flush_cache_range = r4k_flush_cache_range_s128d32i32; + _flush_cache_page = r4k_flush_cache_page_s128d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; break; }; - clear_page = r4k_clear_page_s128; - copy_page = r4k_copy_page_s128; + _clear_page = r4k_clear_page_s128; + _copy_page = r4k_copy_page_s128; break; } - dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; - dma_cache_wback = r4k_dma_cache_wback; - dma_cache_inv = r4k_dma_cache_inv_sc; + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; + _dma_cache_wback = r4k_dma_cache_wback; + _dma_cache_inv = r4k_dma_cache_inv_sc; } typedef int (*probe_func_t)(unsigned long); @@ -2509,24 +2509,23 @@ void __init ld_mmu_r4xx0(void) case CPU_R4700: case CPU_R5000: case CPU_NEVADA: - flush_cache_page = r4k_flush_cache_page_d32i32_r4600; + _flush_cache_page = r4k_flush_cache_page_d32i32_r4600; } - flush_cache_sigtramp = r4k_flush_cache_sigtramp; + _flush_cache_sigtramp = r4k_flush_cache_sigtramp; if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { - flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; + _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; } - flush_tlb_all = r4k_flush_tlb_all; - flush_tlb_mm = r4k_flush_tlb_mm; - flush_tlb_range = r4k_flush_tlb_range; - flush_tlb_page = r4k_flush_tlb_page; + _flush_tlb_all = r4k_flush_tlb_all; + _flush_tlb_mm = r4k_flush_tlb_mm; + _flush_tlb_range = r4k_flush_tlb_range; + _flush_tlb_page = r4k_flush_tlb_page; update_mmu_cache = r4k_update_mmu_cache; - show_regs = r4k_show_regs; - - user_mode = r4k_user_mode; + _show_regs = r4k_show_regs; + _user_mode = r4k_user_mode; flush_cache_all(); write_32bit_cp0_register(CP0_WIRED, 0); diff --git a/arch/mips64/mm/tfp.c b/arch/mips64/mm/tfp.c deleted file mode 100644 index ac38d97c8..000000000 --- a/arch/mips64/mm/tfp.c +++ /dev/null @@ -1,157 +0,0 @@ -/* $Id: tfp.c,v 1.5 2000/01/17 23:32:46 ralf Exp $ - * - * tfp.c: MMU and cache routines specific to the r8000 (TFP). - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> - -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/sgialib.h> -#include <asm/mmu_context.h> - -static void tfp_clear_page(void * page) -{ - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "daddiu\t$1,%0,%2\n" - "1:\tsd\t$0,(%0)\n\t" - "sd\t$0,8(%0)\n\t" - "sd\t$0,16(%0)\n\t" - "sd\t$0,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "sd\t$0,-32(%0)\n\t" - "sd\t$0,-24(%0)\n\t" - "sd\t$0,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - "sd\t$0,-8(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (page) - :"0" (page), "I" (PAGE_SIZE) - :"$1", "memory"); -} - -static void tfp_copy_page(void * to, void * from) -{ - unsigned long dummy1, dummy2, reg1, reg2; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - ".set\tnoat\n\t" - "daddiu\t$1,%0,%6\n" - "1:\tld\t%2,(%1)\n\t" - "ld\t%3,8(%1)\n\t" - "sd\t%2,(%0)\n\t" - "sd\t%3,8(%0)\n\t" - "ld\t%2,16(%1)\n\t" - "ld\t%3,24(%1)\n\t" - "sd\t%2,16(%0)\n\t" - "sd\t%3,24(%0)\n\t" - "daddiu\t%0,64\n\t" - "daddiu\t%1,64\n\t" - "ld\t%2,-32(%1)\n\t" - "ld\t%3,-24(%1)\n\t" - "sd\t%2,-32(%0)\n\t" - "sd\t%3,-24(%0)\n\t" - "ld\t%2,-16(%1)\n\t" - "ld\t%3,-8(%1)\n\t" - "sd\t%2,-16(%0)\n\t" - "bne\t$1,%0,1b\n\t" - " sd\t%3,-8(%0)\n\t" - ".set\tat\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) - :"0" (to), "1" (from), "I" (PAGE_SIZE)); -} - -/* Cache operations. XXX Write these dave... */ -static inline void tfp_flush_cache_all(void) -{ - /* XXX */ -} - -static void tfp_flush_cache_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void tfp_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void tfp_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - /* XXX */ -} - -static void tfp_flush_page_to_ram(struct page * page) -{ - /* XXX */ -} - -static void tfp_flush_cache_sigtramp(unsigned long page) -{ - /* XXX */ -} - -/* TLB operations. XXX Write these dave... */ -static inline void tfp_flush_tlb_all(void) -{ - /* XXX */ -} - -static void tfp_flush_tlb_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void tfp_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void tfp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - /* XXX */ -} - -static int tfp_user_mode(struct pt_regs *regs) -{ - return (regs->cp0_status & ST0_KSU) == KSU_USER; -} - -void __init ld_mmu_tfp(void) -{ - clear_page = tfp_clear_page; - copy_page = tfp_copy_page; - - flush_cache_all = tfp_flush_cache_all; - flush_cache_mm = tfp_flush_cache_mm; - flush_cache_range = tfp_flush_cache_range; - flush_cache_page = tfp_flush_cache_page; - flush_cache_sigtramp = tfp_flush_cache_sigtramp; - flush_page_to_ram = tfp_flush_page_to_ram; - - flush_tlb_all = tfp_flush_tlb_all; - flush_tlb_mm = tfp_flush_tlb_mm; - flush_tlb_range = tfp_flush_tlb_range; - flush_tlb_page = tfp_flush_tlb_page; - - user_mode = tfp_user_mode; - - flush_cache_all(); - flush_tlb_all(); -} diff --git a/arch/mips64/sgi-ip22/ip22-berr.c b/arch/mips64/sgi-ip22/ip22-berr.c index 32797fcf4..ecc3af198 100644 --- a/arch/mips64/sgi-ip22/ip22-berr.c +++ b/arch/mips64/sgi-ip22/ip22-berr.c @@ -1,4 +1,4 @@ -/* $Id: ip22-berr.c,v 1.1 2000/01/21 21:35:46 ralf Exp $ +/* $Id: ip22-berr.c,v 1.1 2000/01/21 22:34:03 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -12,6 +12,7 @@ #include <asm/uaccess.h> #include <asm/paccess.h> #include <asm/addrspace.h> +#include <asm/ptrace.h> extern asmlinkage void handle_ibe(void); extern asmlinkage void handle_dbe(void); diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S index 7defc69e8..05639bdd1 100644 --- a/arch/ppc/coffboot/misc.S +++ b/arch/ppc/coffboot/misc.S @@ -9,7 +9,7 @@ .text /* - * Use the BAT0 registers to map the 1st 8MB of RAM to + * Use the BAT3 registers to map the 1st 8MB of RAM to * the address given as the 1st argument. */ .globl setup_bats diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 8ea7e9000..8bb23afa2 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -97,7 +97,7 @@ fi if [ "$CONFIG_6xx" = "y" -a "$CONFIG_APUS" != "y" ]; then define_bool CONFIG_PCI y fi -if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y"]; then +if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then define_bool CONFIG_PCI y fi diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index ac258f16e..17217702f 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -24,7 +24,7 @@ CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_SMP is not set -# CONFIG_ALTIVEC is not set +CONFIG_ALTIVEC=y # # Loadable module support @@ -76,7 +76,7 @@ CONFIG_BOOTX_TEXT=y # # Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # @@ -178,9 +178,12 @@ CONFIG_SCSI=y # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y # @@ -239,6 +242,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -275,6 +279,7 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y +CONFIG_GMAC=y # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set @@ -472,6 +477,7 @@ CONFIG_USB=y # USB Controllers # # CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y # @@ -491,8 +497,7 @@ CONFIG_USB_OHCI=y # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set -CONFIG_USB_SCSI=m -CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # @@ -513,11 +518,15 @@ CONFIG_USB_MOUSE=y # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set +CONFIG_HFS_FS=y # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y @@ -549,10 +558,51 @@ CONFIG_LOCKD=y # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set # # Sound diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig index 6fe267c9a..90cc5b71f 100644 --- a/arch/ppc/configs/gemini_defconfig +++ b/arch/ppc/configs/gemini_defconfig @@ -24,7 +24,7 @@ CONFIG_6xx=y CONFIG_GEMINI=y # CONFIG_APUS is not set # CONFIG_SMP is not set -# CONFIG_ALTIVEC is not set +CONFIG_ALTIVEC=y CONFIG_MACH_SPECIFIC=y # @@ -87,7 +87,6 @@ CONFIG_KERNEL_ELF=y # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set # CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set @@ -151,9 +150,12 @@ CONFIG_SCSI=y # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 # CONFIG_CHR_DEV_SG is not set # @@ -208,6 +210,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -216,6 +219,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_MESH is not set # CONFIG_SCSI_MAC53C94 is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # IEEE 1394 (FireWire) support @@ -242,6 +246,7 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y # CONFIG_MACE is not set # CONFIG_BMAC is not set +# CONFIG_GMAC is not set CONFIG_NCR885E=y # CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set @@ -369,6 +374,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set @@ -405,10 +411,7 @@ CONFIG_LOCKD=y # Partition Types # # CONFIG_PARTITION_ADVANCED is not set -CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index ac258f16e..17217702f 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -24,7 +24,7 @@ CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_SMP is not set -# CONFIG_ALTIVEC is not set +CONFIG_ALTIVEC=y # # Loadable module support @@ -76,7 +76,7 @@ CONFIG_BOOTX_TEXT=y # # Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # @@ -178,9 +178,12 @@ CONFIG_SCSI=y # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y # @@ -239,6 +242,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -275,6 +279,7 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y +CONFIG_GMAC=y # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set @@ -472,6 +477,7 @@ CONFIG_USB=y # USB Controllers # # CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y # @@ -491,8 +497,7 @@ CONFIG_USB_OHCI=y # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set -CONFIG_USB_SCSI=m -CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # @@ -513,11 +518,15 @@ CONFIG_USB_MOUSE=y # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set +CONFIG_HFS_FS=y # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y @@ -549,10 +558,51 @@ CONFIG_LOCKD=y # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set # # Sound diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 2d1238a6b..013812afc 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -176,7 +176,7 @@ ret_from_syscall_2: 7: .string "syscall %d(%x, %x, %x, %x, %x, " 77: .string "%x, %x), current=%p\n" 79: .string " -> %x\n" - .align 2 + .align 2,0 #endif /* @@ -209,6 +209,9 @@ _GLOBAL(_switch) mflr r20 /* Return to switch caller */ mfmsr r22 li r0,MSR_FP /* Disable floating-point */ +#ifdef CONFIG_ALTIVEC + oris r0,r0,MSR_VEC@h +#endif /* CONFIG_ALTIVEC */ andc r22,r22,r0 stw r20,_NIP(r1) stw r22,_MSR(r1) @@ -274,7 +277,7 @@ _GLOBAL(_switch) SYNC rfi -#ifdef __SMP__ +#ifdef CONFIG_SMP .globl ret_from_smpfork ret_from_smpfork: bl schedule_tail @@ -310,22 +313,32 @@ ret_from_except: lwz r5,_MSR(r1) andi. r5,r5,MSR_EE beq 2f + .globl lost_irq_ret +lost_irq_ret: 3: lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) cmpi 0,r4,0 beq+ 1f addi r3,r1,STACK_FRAME_OVERHEAD bl do_IRQ - .globl lost_irq_ret -lost_irq_ret: b 3b -1: lis r4,bh_mask@ha - lwz r4,bh_mask@l(r4) - lis r5,bh_active@ha - lwz r5,bh_active@l(r5) - and. r4,r4,r5 +1: lis r4,softirq_state@ha + addi r4,r4,softirq_state@l +#ifdef CONFIG_SMP + /* get processor # */ + lwz r3,PROCESSOR(r2) +#ifndef CONFIG_PPC64 + slwi r3,r3,5 +#else +#error not 64-bit ready +#endif + add r4,r4,r3 +#endif /* CONFIG_SMP */ + lwz r5,0(r4) + lwz r4,4(r4) + and. r5,r5,r4 beq+ 2f - bl do_bottom_half + bl do_softirq .globl do_bottom_half_ret do_bottom_half_ret: 2: /* disable interrupts */ diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 8b56c635c..dd16b8c27 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -460,8 +460,24 @@ SystemCall: STD_EXCEPTION(0xd00, SingleStep, SingleStepException) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) -#ifdef CONFIG_ALTIVEC - STD_EXCEPTION(0xf20, AltiVec, AltiVecUnavailable) +#ifndef CONFIG_ALTIVEC + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) +#else +/* + * The Altivec unavailable trap is at 0x0f20. Foo. + * We effectively remap it to 0x3000. + */ + . = 0xf00 + b Trap_0f +trap_0f_cont: + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + bl transfer_to_handler + .long UnknownException + .long ret_from_except + + . = 0xf20 + b AltiVecUnavailable #endif /* CONFIG_ALTIVEC */ /* @@ -674,6 +690,21 @@ DataStoreTLBMiss: . = 0x3000 +#ifdef CONFIG_ALTIVEC +AltiVecUnavailable: + EXCEPTION_PROLOG + bne load_up_altivec /* if from user, just load it up */ + li r20,MSR_KERNEL + bl transfer_to_handler /* if from kernel, take a trap */ + .long KernelAltiVec + .long ret_from_except + +/* here are the bits of trap 0xf00 which got displaced */ +Trap_0f: + EXCEPTION_PROLOG + b trap_0f_cont +#endif /* CONFIG_ALTIVEC */ + /* * This code finishes saving the registers to the exception frame * and jumps to the appropriate handler for the exception, turning @@ -813,72 +844,134 @@ KernelFP: 86: .string "floating point used in kernel (task=%p, pc=%x)\n" .align 4 +#ifdef CONFIG_ALTIVEC +/* Note that the AltiVec support is closely modeled after the FP + * support. Changes to one are likely to be applicable to the + * other! */ +load_up_altivec: /* - * Take away the altivec regs. - * - * For now, ignore the vrsave regs and save them all - * -- Cort + * Disable AltiVec for the task which had AltiVec previously, + * and save its AltiVec registers in its thread_struct. + * Enables AltiVec for use in the kernel on return. + * On SMP we know the AltiVec units are free, since we give it up every + * switch. -- Kumar */ - .globl giveup_altivec -giveup_altivec: -#ifdef CONFIG_ALTIVEC - /* check for altivec */ - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,12 - bnelr - - /* enable altivec so we can save */ - mfmsr r4 - oris r4,r4,MSR_VEC@h - mtmsr r4 + mfmsr r5 + oris r5,r5,MSR_VEC@h + SYNC + mtmsr r5 /* enable use of AltiVec now */ + SYNC +/* + * For SMP, we don't do lazy AltiVec switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_altivec in switch_to. + */ +#ifndef __SMP__ +#ifndef CONFIG_APUS + lis r6,-KERNELBASE@h +#else + lis r6,CYBERBASEp@h + lwz r6,0(r6) +#endif + addis r3,r6,last_task_used_altivec@ha + lwz r4,last_task_used_altivec@l(r3) + cmpi 0,r4,0 + beq 1f + add r4,r4,r6 + addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ + SAVE_32VR(0,r20,r4) + MFVSCR(vr0) + li r20,THREAD_VSCR + STVX(vr0,r20,r4) + lwz r5,PT_REGS(r4) + add r5,r5,r6 + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r20,MSR_VEC@h + andc r4,r4,r20 /* disable altivec for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* __SMP__ */ + /* enable use of AltiVec after return */ + oris r23,r23,MSR_VEC@h + mfspr r5,SPRG3 /* current task's THREAD (phys) */ + li r20,THREAD_VSCR + LVX(vr0,r20,r5) + MTVSCR(vr0) + REST_32VR(0,r20,r5) +#ifndef __SMP__ + subi r4,r5,THREAD + sub r4,r4,r6 + stw r4,last_task_used_altivec@l(r3) +#endif /* __SMP__ */ + /* restore registers and return */ + lwz r3,_CCR(r21) + lwz r4,_LINK(r21) + mtcrf 0xff,r3 + mtlr r4 + REST_GPR(1, r21) + REST_4GPRS(3, r21) + /* we haven't used ctr or xer */ + mtspr SRR1,r23 + mtspr SRR0,r22 + REST_GPR(20, r21) + REST_2GPRS(22, r21) + lwz r21,GPR21(r21) + SYNC + rfi - /* make sure our tsk pointer is valid */ - cmpi 0,r3,0 - beqlr +/* + * AltiVec unavailable trap from kernel - print a message, but let + * the task use AltiVec in the kernel until it returns to user mode. + */ +KernelAltiVec: + lwz r3,_MSR(r1) + oris r3,r3,MSR_VEC@h + stw r3,_MSR(r1) /* enable use of AltiVec after return */ + lis r3,87f@h + ori r3,r3,87f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +87: .string "AltiVec used in kernel (task=%p, pc=%x) \n" + .align 4 - /* save altivec regs */ - addi r4,r3,THREAD+THREAD_VRSAVE - mfspr r5,256 /* vrsave */ - stw r5,0(r4) - - /* get regs for the task */ - addi r4,r3,THREAD+PT_REGS - /* turn off the altivec bit in the tasks regs */ - lwz r5,_MSR(r4) - lis r6,MSR_VEC@h - andi. r5,r5,r6 - stw r5,_MSR(r4) - - /* we've given up the altivec - clear the pointer */ - li r3,0 - lis r4,last_task_used_altivec@h - stw r3,last_task_used_altivec@l(r4) -#endif /* CONFIG_ALTIVEC */ - blr - - .globl load_up_altivec -load_up_altivec: -#ifdef CONFIG_ALTIVEC - /* check for altivec */ - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,12 - bnelr - - /* restore altivec regs */ - addi r4,r3,THREAD+THREAD_VRSAVE - lwz r5,0(r4) - mtspr 256,r5 /* vrsave */ - - /* get regs for the task */ - addi r4,r3,THREAD+PT_REGS - /* turn on the altivec bit in the tasks regs */ - lwz r5,_MSR(r4) +/* + * giveup_altivec(tsk) + * Disable AltiVec for the task given as the argument, + * and save the AltiVec registers in its thread_struct. + * Enables AltiVec for use in the kernel on return. + */ + + .globl giveup_altivec +giveup_altivec: + mfmsr r5 oris r5,r5,MSR_VEC@h - stw r5,_MSR(r4) -#endif /* CONFIG_ALTIVEC */ + SYNC + mtmsr r5 /* enable use of AltiVec now */ + SYNC + cmpi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32VR(0, r4, r3) + MFVSCR(vr0) + li r4,THREAD_VSCR + STVX(vr0, r4, r3) + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r3,MSR_VEC@h + andc r4,r4,r3 /* disable AltiVec for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef __SMP__ + li r5,0 + lis r4,last_task_used_altivec@ha + stw r5,last_task_used_altivec@l(r4) +#endif /* __SMP__ */ blr +#endif /* CONFIG_ALTIVEC */ /* * giveup_fpu(tsk) @@ -1437,17 +1530,16 @@ mmu_off: #if 0 /* That's useful debug stuff */ setup_screen_bat: + li r3,0 + mtspr DBAT1U,r3 + mtspr IBAT1U,r3 lis r3, 0x9100 -#ifdef __SMP__ - ori r3,r3,0x12 -#else - ori r3,r3,0x2 -#endif - mtspr DBAT1L, r3 - mtspr IBAT1L, r3 + ori r4,r3,0x2a + mtspr DBAT1L,r4 + mtspr IBAT1L,r4 ori r3,r3,(BL_8M<<2)|0x2 /* set up BAT registers for 604 */ - mtspr DBAT1U, r3 - mtspr IBAT1U, r3 + mtspr DBAT1U,r3 + mtspr IBAT1U,r3 blr #endif diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 8b5f590fb..fd77fbc36 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -74,8 +74,8 @@ volatile unsigned char *chrp_int_ack_special; irq_desc_t irq_desc[NR_IRQS]; int ppc_spurious_interrupts = 0; -unsigned int ppc_local_bh_count[NR_CPUS]; -unsigned int ppc_local_irq_count[NR_CPUS]; +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; struct irqaction *ppc_irq_action[NR_IRQS]; unsigned int ppc_cached_irq_mask[NR_MASK_WORDS]; unsigned int ppc_lost_interrupts[NR_MASK_WORDS]; @@ -350,7 +350,6 @@ unsigned volatile int global_irq_lock; atomic_t global_irq_count; atomic_t global_bh_count; -atomic_t global_bh_lock; static void show(char * str) { @@ -361,12 +360,12 @@ static void show(char * str) printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [%d %d]\n", atomic_read(&global_irq_count), - ppc_local_irq_count[0], - ppc_local_irq_count[1]); + local_irq_count[0], + local_irq_count[1]); printk("bh: %d [%d %d]\n", atomic_read(&global_bh_count), - ppc_local_bh_count[0], - ppc_local_bh_count[1]); + local_bh_count[0], + local_bh_count[1]); stack = (unsigned long *) &str; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -401,7 +400,7 @@ static inline void wait_on_irq(int cpu) * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (ppc_local_bh_count[cpu] + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) break; } @@ -423,7 +422,7 @@ static inline void wait_on_irq(int cpu) continue; if (global_irq_lock) continue; - if (!ppc_local_bh_count[cpu] + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) continue; if (!test_and_set_bit(0,&global_irq_lock)) @@ -514,7 +513,7 @@ void __global_cli(void) if (flags & (1 << 15)) { int cpu = smp_processor_id(); __cli(); - if (!ppc_local_irq_count[cpu]) + if (!local_irq_count[cpu]) get_irqlock(cpu); } } @@ -523,7 +522,7 @@ void __global_sti(void) { int cpu = smp_processor_id(); - if (!ppc_local_irq_count[cpu]) + if (!local_irq_count[cpu]) release_irqlock(cpu); __sti(); } @@ -547,7 +546,7 @@ unsigned long __global_save_flags(void) retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!ppc_local_irq_count[smp_processor_id()]) { + if (!local_irq_count[smp_processor_id()]) { if (local_enabled) retval = 1; if (global_irq_holder == (unsigned char) smp_processor_id()) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index fde7112c7..50f63eeb4 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -229,7 +229,7 @@ _GLOBAL(flush_dcache_range) blr /* - * Flush a particular page from the DATA cache + * Flush a particular page from the data cache to RAM. * Note: this is necessary because the instruction cache does *not* * snoop from the data cache. * This is a no-op on the 601 which has a unified cache. @@ -241,18 +241,31 @@ _GLOBAL(__flush_page_to_ram) rlwinm r5,r5,16,16,31 cmpi 0,r5,1 beqlr /* for 601, do nothing */ - li r4,0x0FFF - andc r3,r3,r4 /* Get page base address */ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 - mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ addi r3,r3,CACHE_LINE_SIZE bdnz 0b sync + blr + +/* + * Flush a particular page from the instruction cache. + * Note: this is necessary because the instruction cache does *not* + * snoop from the data cache. + * This is a no-op on the 601 which has a unified cache. + * + * void __flush_icache_page(void *page) + */ +_GLOBAL(__flush_icache_page) + mfspr r5,PVR + rlwinm r5,r5,16,16,31 + cmpi 0,r5,1 + beqlr /* for 601, do nothing */ + li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 -1: icbi 0,r6 - addi r6,r6,CACHE_LINE_SIZE +1: icbi 0,r3 + addi r3,r3,CACHE_LINE_SIZE bdnz 1b sync isync @@ -272,6 +285,38 @@ _GLOBAL(clear_page) blr /* + * Copy a whole page. We use the dcbz instruction on the destination + * to reduce memory traffic (it eliminates the unnecessary reads of + * the destination into cache). This requires that the destination + * is cacheable. + */ +_GLOBAL(copy_page) + li r0,4096/CACHE_LINE_SIZE + mtctr r0 + addi r3,r3,-4 + addi r4,r4,-4 + li r5,4 +1: dcbz r5,r3 + lwz r6,4(r4) + lwz r7,8(r4) + lwz r8,12(r4) + lwzu r9,16(r4) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + stwu r9,16(r3) + lwz r6,4(r4) + lwz r7,8(r4) + lwz r8,12(r4) + lwzu r9,16(r4) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + stwu r9,16(r3) + bdnz 1b + blr + +/* * Atomic [test&set] exchange * * unsigned long xchg_u32(void *ptr, unsigned long val) diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c index 34682bd2a..4f3c6834d 100644 --- a/arch/ppc/kernel/mk_defs.c +++ b/arch/ppc/kernel/mk_defs.c @@ -9,6 +9,7 @@ */ #include <stddef.h> +#include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -48,9 +49,11 @@ main(void) DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); - DEFINE(THREAD_VRF, offsetof(struct thread_struct, vrf)); - DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); +#ifdef CONFIG_ALTIVEC + DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); + DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); +#endif /* CONFIG_ALTIVEC */ /* Interrupt register frame */ DEFINE(TASK_UNION_SIZE, sizeof(union task_union)); DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index d4dbe05e5..301a82ba8 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -279,7 +279,7 @@ void __init openpic_init(int main_pic) /* Initialize the spurious interrupt */ if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd); openpic_set_spurious(OPENPIC_VEC_SPURIOUS); - if ( !(_machine && (_MACH_gemini|_MACH_Pmac)) ) + if ( !(_machine & (_MACH_gemini|_MACH_Pmac)) ) { if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, "82c59 cascade", NULL)) @@ -490,7 +490,7 @@ void openpic_enable_irq(u_int irq) /* make sure mask gets to controller before we return to user */ do { mb(); /* sync is probably useless here */ - } while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + } while(openpic_readfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK)); } @@ -501,7 +501,7 @@ void openpic_disable_irq(u_int irq) /* make sure mask gets to controller before we return to user */ do { mb(); /* sync is probably useless here */ - } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + } while(!openpic_readfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK)); } diff --git a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c index 089566908..174de223f 100644 --- a/arch/ppc/kernel/pci-dma.c +++ b/arch/ppc/kernel/pci-dma.c @@ -14,20 +14,6 @@ #include <linux/pci.h> #include <asm/io.h> -/* Pure 2^n version of get_order */ -extern __inline__ int __get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { @@ -36,7 +22,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, __get_order(size)); + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); @@ -48,5 +34,5 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, __get_order(size)); + free_pages((unsigned long)vaddr, get_order(size)); } diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index d2d5e6b25..d13875c9f 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -31,8 +31,6 @@ static int max_irqs; static int max_real_irqs; static int has_openpic = 0; -#define MAXCOUNT 10000000 - #define GATWICK_IRQ_POOL_SIZE 10 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; @@ -187,25 +185,6 @@ pmac_get_irq(struct pt_regs *regs) smp_message_recv(); return -2; /* ignore, already handled */ } - - { - unsigned int loops = MAXCOUNT; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } #endif /* __SMP__ */ /* Yeah, I know, this could be a separate do_IRQ function */ diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index e1c1815ac..5fef07e89 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -60,6 +60,7 @@ #include <asm/machdep.h> #include <asm/keyboard.h> #include <asm/dma.h> +#include <asm/bootx.h> #include "time.h" #include "local_irq.h" @@ -440,6 +441,7 @@ kdev_t __init find_ide_boot(void) { char *p; int n; + kdev_t __init pmac_find_ide_boot(char *bootdevice, int n); if (bootdevice == NULL) return 0; @@ -695,9 +697,12 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, #ifdef CONFIG_BOOTX_TEXT extern void drawchar(char c); extern void drawstring(const char *c); +extern boot_infos_t *disp_bi; void pmac_progress(char *s, unsigned short hex) { + if (disp_bi == 0) + return; drawstring(s); drawchar('\n'); } diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index 1c935a625..3b7dd283f 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -71,8 +71,8 @@ unsigned long pmac_get_rtc_time(void) if (req.reply_len != 7) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (unsigned long)(req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + (unsigned long)req.reply[4] - RTC_OFFSET; + return (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: diff --git a/arch/ppc/kernel/ppc_asm.h b/arch/ppc/kernel/ppc_asm.h index 2b999ab36..d9093c9e1 100644 --- a/arch/ppc/kernel/ppc_asm.h +++ b/arch/ppc/kernel/ppc_asm.h @@ -44,6 +44,28 @@ #define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) #define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) +/* + * Once a version of gas that understands the AltiVec instructions + * is freely available, we can do this the normal way... - paulus + */ +#define LVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1) +#define STVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1) +#define MFVSCR(r) .long (4<<26)+((r)<<21)+(1540<<1) +#define MTVSCR(r) .long (4<<26)+((r)<<11)+(802<<1) + +#define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); STVX(n,b,base) +#define SAVE_2VR(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) +#define SAVE_4VR(n,b,base) SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) +#define SAVE_8VR(n,b,base) SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) +#define SAVE_16VR(n,b,base) SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base) +#define SAVE_32VR(n,b,base) SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base) +#define REST_VR(n,b,base) li b,THREAD_VR0+(16*(n)); LVX(n,b,base) +#define REST_2VR(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) +#define REST_4VR(n,b,base) REST_2VR(n,b,base); REST_2VR(n+2,b,base) +#define REST_8VR(n,b,base) REST_4VR(n,b,base); REST_4VR(n+4,b,base) +#define REST_16VR(n,b,base) REST_8VR(n,b,base); REST_8VR(n+8,b,base) +#define REST_32VR(n,b,base) REST_16VR(n,b,base); REST_16VR(n+16,b,base) + #define SYNC \ sync; \ isync diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl index 94a5bd74c..c35192bb4 100644 --- a/arch/ppc/kernel/ppc_asm.tmpl +++ b/arch/ppc/kernel/ppc_asm.tmpl @@ -80,3 +80,36 @@ #define fr29 29 #define fr30 30 #define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 9a5444a51..757715512 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -11,6 +11,7 @@ #include <linux/spinlock.h> #include <linux/console.h> #include <linux/irq.h> +#include <linux/pci.h> #include <asm/page.h> #include <asm/semaphore.h> @@ -72,8 +73,8 @@ EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); -EXPORT_SYMBOL(ppc_local_irq_count); -EXPORT_SYMBOL(ppc_local_bh_count); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); #ifdef __SMP__ EXPORT_SYMBOL(kernel_flag); #endif /* __SMP__ */ @@ -171,6 +172,11 @@ EXPORT_SYMBOL(chrp_ide_regbase); EXPORT_SYMBOL(chrp_ide_probe); #endif +#ifdef CONFIG_PCI +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); +#endif /* CONFIG_PCI */ + EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); @@ -272,4 +278,3 @@ EXPORT_SYMBOL(ppc_irq_dispatch_handler); EXPORT_SYMBOL(decrementer_count); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); -EXPORT_SYMBOL(do_bottom_half); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index ed98ba6f0..41382b2d7 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -19,6 +19,7 @@ * */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -140,15 +141,31 @@ int check_stack(struct task_struct *tsk) } #endif /* defined(CHECK_STACK) */ +#ifdef CONFIG_ALTIVEC int -dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) { - if (regs->msr & MSR_FP) - giveup_fpu(current); - memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); + if (regs->msr & MSR_VEC) + giveup_altivec(current); + memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); return 1; } +void +enable_kernel_altivec(void) +{ +#ifdef __SMP__ + if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) + giveup_altivec(current); + else + giveup_altivec(NULL): /* just enable AltiVec for kernel - force */ +#else + giveup_altivec(last_task_used_altivec); +#endif /* __SMP __ */ + printk("MSR_VEC in enable_altivec_kernel\n"); +} +#endif /* CONFIG_ALTIVEC */ + void enable_kernel_fp(void) { @@ -162,6 +179,15 @@ enable_kernel_fp(void) #endif /* __SMP__ */ } +int +dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +{ + if (regs->msr & MSR_FP) + giveup_fpu(current); + memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); + return 1; +} + void _switch_to(struct task_struct *prev, struct task_struct *new, struct task_struct **last) @@ -194,6 +220,7 @@ _switch_to(struct task_struct *prev, struct task_struct *new, */ if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) ) giveup_fpu(prev); +#ifdef CONFIG_ALTIVEC /* * If the previous thread 1) has some altivec regs it wants saved * (has bits in vrsave set) and 2) used altivec in the last quantum @@ -206,6 +233,7 @@ _switch_to(struct task_struct *prev, struct task_struct *new, if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) && prev->thread.vrsave ) giveup_altivec(prev); +#endif /* CONFIG_ALTIVEC */ prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* __SMP__ */ @@ -337,13 +365,18 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, p->thread.fpscr = current->thread.fpscr; childregs->msr &= ~MSR_FP; +#ifdef CONFIG_ALTIVEC + /* + * copy altiVec info - assume lazy altiVec switch + * - kumar + */ if (regs->msr & MSR_VEC) giveup_altivec(current); - if ( p->thread.vrsave ) - memcpy(&p->thread.vrf, ¤t->thread.vrf, sizeof(p->thread.vrf)); + + memcpy(&p->thread.vr, ¤t->thread.vr, sizeof(p->thread.vr)); p->thread.vscr = current->thread.vscr; - p->thread.vrsave = current->thread.vrsave; childregs->msr &= ~MSR_VEC; +#endif /* CONFIG_ALTIVEC */ #ifdef __SMP__ p->last_processor = NO_PROC_ID; @@ -463,6 +496,10 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, goto out; if (regs->msr & MSR_FP) giveup_fpu(current); +#ifdef CONFIG_ALTIVEC + if (regs->msr & MSR_VEC) + giveup_altivec(current); +#endif /* CONFIG_ALTIVEC */ error = do_execve(filename, (char **) a1, (char **) a2, regs); putname(filename); out: diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index a52bdd804..b86e2a153 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -802,42 +802,19 @@ setup_disp_fake_bi(ihandle dp) { unsigned int len; int width = 640, height = 480, depth = 8, pitch; - unsigned address; + unsigned address; boot_infos_t* bi; unsigned long offset = reloc_offset(); - prom_print(RELOC("Initing fake screen\n")); + prom_print(RELOC("Initializing fake screen\n")); - len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height)); call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len)); - if (len == 0) - prom_print(RELOC("Warning: assuming display depth = 8\n")); - else - depth = len; - width = len = 0; - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len)); - width = len; - if (width == 0) { - prom_print(RELOC("Failed to get width\n")); - return; - } - height = len = 0; - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len)); - height = len; - if (height == 0) { - prom_print(RELOC("Failed to get height\n")); - return; - } - pitch = len = 0; + pitch = width * ((depth + 7) / 8); call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len)); - pitch = len; - if (pitch == 0) { - prom_print(RELOC("Failed to get pitch\n")); - return; - } - address = len = 0; + address = 0; call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len)); - address = len; if (address == 0) { prom_print(RELOC("Failed to get address\n")); return; @@ -846,22 +823,22 @@ setup_disp_fake_bi(ihandle dp) /* kludge for valkyrie */ if (strcmp(dp->name, "valkyrie") == 0) address += 0x1000; - } #endif - RELOC(disp_bi) = &fake_bi; - bi = PTRRELOC((&fake_bi)); - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; - bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = (unsigned char *)address; - bi->dispDeviceRowBytes = pitch; - bi->dispDeviceDepth = depth; - bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; + RELOC(disp_bi) = &fake_bi; + bi = PTRRELOC((&fake_bi)); + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = width / 8; + RELOC(g_max_loc_Y) = height / 16; + bi->logicalDisplayBase = (unsigned char *)address; + bi->dispDeviceBase = (unsigned char *)address; + bi->dispDeviceRowBytes = pitch; + bi->dispDeviceDepth = depth; + bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; + bi->dispDeviceRect[2] = width; + bi->dispDeviceRect[3] = height; + RELOC(disp_bi) = 0; } #endif diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 19ce0a25e..7502ad08e 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -221,7 +221,7 @@ int get_cpuinfo(char *buffer) if ( i ) len += sprintf(len+buffer,"\n"); len += sprintf(len+buffer,"processor\t: %lu\n",i); - len += sprintf(len+buffer,"cpu\t\t: "); + len += sprintf(len+buffer,"cpu\t\t: "); pvr = GET_PVR; @@ -656,7 +656,6 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_BOOTX_TEXT map_bootx_text(); - prom_print("identify machine\n"); #endif #ifdef CONFIG_XMON diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 386764ddd..83dff9246 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -53,7 +53,6 @@ unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; /* all cpu mappings are 1-1 -- Cort */ -int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,}; volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; int start_secondary(void *); diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index e1a3fdcbb..e31b34cc9 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -252,14 +252,13 @@ asmlinkage int sys_pause(void) asmlinkage int sys_uname(struct old_utsname * name) { - int err; - - if (!name) - return -EFAULT; + int err = -EFAULT; + down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); - up(&uts_sem); - return err ? -EFAULT : 0; + if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + err = 0; + up_read(&uts_sem); + return err; } asmlinkage int sys_olduname(struct oldold_utsname * name) @@ -282,8 +281,8 @@ asmlinkage int sys_olduname(struct oldold_utsname * name) error -= __put_user(0,name->version+__OLD_UTS_LEN); error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); - error = error ? -EFAULT : 0; - up(&uts_sem); + up_read(&uts_sem); + error = error ? -EFAULT : 0; return error; } diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 5cc34c5a5..ac7f47602 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -118,11 +118,11 @@ MachineCheckException(struct pt_regs *regs) default: printk("Unknown values in msr\n"); } + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); #endif - show_regs(regs); - print_backtrace((unsigned long *)regs->gpr[1]); panic("machine check"); } _exception(SIGSEGV, regs); @@ -142,44 +142,6 @@ SMIException(struct pt_regs *regs) panic("System Management Interrupt"); } -#if defined(CONFIG_ALTIVEC) -void -AltiVecUnavailable(struct pt_regs *regs) -{ - /* - * This should be changed so we don't take a trap if coming - * back when last_task_used_altivec == current. We should also - * allow the kernel to use the altivec regs on UP to store tasks - * regs during switch - * -- Cort - */ - if ( regs->msr & MSR_VEC ) - { - show_regs(regs); - panic("AltiVec trap with Altivec enabled!\n"); - } - - if ( !user_mode(regs) ) - { - show_regs(regs); - panic("Kernel Used Altivec with MSR_VEC off!\n"); - } - - if ( last_task_used_altivec != current ) - { - if ( last_task_used_altivec ) - giveup_altivec(current); - load_up_altivec(current); - /* on SMP we always save/restore on switch */ -#ifndef __SMP__ - last_task_used_altivec = current; -#endif - } - /* enable altivec for the task on return */ - regs->msr |= MSR_VEC; -} -#endif /* CONFIG_ALTIVEC */ - void UnknownException(struct pt_regs *regs) { diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 4ab90f8b7..1c4f1f78e 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -12,6 +12,11 @@ #include <asm/processor.h> #include <asm/errno.h> +CACHELINE_BYTES = 32 +LG_CACHELINE_BYTES = 5 +CACHELINE_MASK = 0x1f +CACHELINE_WORDS = 8 + .globl strcpy strcpy: addi r5,r3,-1 @@ -70,6 +75,55 @@ strlen: subf r3,r3,r4 blr +/* + * Use dcbz on the complete cache lines in the destination + * to set them to zero. This requires that the destination + * area is cacheable. -- paulus + */ + .globl cacheable_memzero +cacheable_memzero: + mr r5,r4 + li r4,0 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + clrlwi r7,r6,32-LG_CACHELINE_BYTES + add r8,r7,r5 + srwi r9,r8,LG_CACHELINE_BYTES + addic. r9,r9,-1 /* total number of complete cachelines */ + ble 2f + xori r0,r7,CACHELINE_MASK & ~3 + srwi. r0,r0,2 + beq 3f + mtctr r0 +4: stwu r4,4(r6) + bdnz 4b +3: mtctr r9 + li r7,4 +10: dcbz r7,r6 + addi r6,r6,CACHELINE_BYTES + bdnz 10b + clrlwi r5,r8,32-LG_CACHELINE_BYTES + addi r5,r5,4 +2: srwi r0,r5,2 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + .globl memset memset: rlwimi r4,r4,8,16,23 @@ -82,7 +136,7 @@ memset: andi. r0,r6,3 add r5,r0,r5 subf r6,r0,r6 - rlwinm r0,r5,32-2,2,31 + srwi r0,r5,2 mtctr r0 bdz 6f 1: stwu r4,4(r6) @@ -103,6 +157,87 @@ bcopy: mr r4,r6 b memcpy +/* + * This version uses dcbz on the complete cache lines in the + * destination area to reduce memory traffic. This requires that + * the destination area is cacheable. + * We only use this version if the source and dest don't overlap. + * -- paulus. + */ + .global cacheable_memcpy +cacheable_memcpy: + add r7,r3,r5 /* test if the src & dst overlap */ + add r8,r4,r5 + cmplw 0,r4,r7 + cmplw 1,r3,r8 + crand 0,0,4 /* cr0.lt &= cr1.lt */ + blt memcpy /* if regions overlap */ + + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + subf r5,r0,r5 + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ + stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ + stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + mtctr r0 + beq 63f +53: dcbz r11,r6 + lwz r7,4(r4) + lwz r8,8(r4) + lwz r9,12(r4) + lwzu r10,16(r4) + stw r7,4(r6) + stw r8,8(r6) + stw r9,12(r6) + stwu r10,16(r6) + lwz r7,4(r4) + lwz r8,8(r4) + lwz r9,12(r4) + lwzu r10,16(r4) + stw r7,4(r6) + stw r8,8(r6) + stw r9,12(r6) + stwu r10,16(r6) + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) + stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) + stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: blr + .globl memmove memmove: cmplw 0,r3,r4 @@ -111,7 +246,7 @@ memmove: .globl memcpy memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + srwi. r7,r5,3 addi r6,r3,-4 addi r4,r4,-4 beq 2f /* if less than 8 bytes to do */ @@ -218,106 +353,167 @@ memchr: .globl __copy_tofrom_user __copy_tofrom_user: - srwi. r7,r5,3 - addi r6,r3,-4 addi r4,r4,-4 - li r3,0 /* success return value */ - beq 2f /* if less than 8 bytes to do */ - andi. r0,r6,3 /* get dest word aligned */ - mtctr r7 - bne 5f -1: lwz r7,4(r4) -11: lwzu r8,8(r4) -12: stw r7,4(r6) -13: stwu r8,8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f -14: lwzu r0,4(r4) - addi r5,r5,-4 -15: stwu r0,4(r6) -3: cmpwi 0,r5,0 /* do 1 byte at a time for the remainder */ - beqlr - mtctr r5 - addi r4,r4,3 - addi r6,r6,3 -4: lbzu r0,1(r4) -16: stbu r0,1(r6) - bdnz 4b - blr -5: subfic r0,r0,4 /* copy bytes until we have the */ - mtctr r0 /* destination 4-byte aligned */ - subf r5,r0,r5 -6: lbz r7,4(r4) + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ +71: stb r9,4(r6) addi r4,r4,1 -17: stb r7,4(r6) addi r6,r6,1 - bdnz 6b - srwi. r7,r5,3 - beq 2b - mtctr r7 - b 1b -/* we come here on a fault in the 8-byte-at-a-time loop */ -88: subi r4,r4,8 /* compensate for the lwzu */ -98: mfctr r0 - rlwimi r5,r0,3,0,28 /* use the byte-at-a-time loop to */ - b 3b /* copy up to the byte at fault */ -/* here on a write fault in the single-word copy */ -96: subi r4,r4,4 - b 3b -/* here on a read fault in the initial single-byte copy */ -90: mfctr r3 - add r3,r3,r5 - b 70f -/* here on a read fault in the final single-byte copy */ -99: mfctr r3 - subi r6,r6,3 -/* clear out the rest of the destination: r3 bytes starting at 4(r6) */ -70: li r0,0 - mr. r5,r3 - beq 76f -71: andi. r4,r6,3 - beq 72f -77: stb r0,4(r6) + bdnz 70b +61: subf r5,r0,r5 + srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ +73: stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + mtctr r0 + beq 63f +53: dcbz r11,r6 +10: lwz r7,4(r4) +11: lwz r8,8(r4) +12: lwz r9,12(r4) +13: lwzu r10,16(r4) +14: stw r7,4(r6) +15: stw r8,8(r6) +16: stw r9,12(r6) +17: stwu r10,16(r6) +20: lwz r7,4(r4) +21: lwz r8,8(r4) +22: lwz r9,12(r4) +23: lwzu r10,16(r4) +24: stw r7,4(r6) +25: stw r8,8(r6) +26: stw r9,12(r6) +27: stwu r10,16(r6) + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) +31: stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) +41: stb r0,4(r6) + addi r4,r4,1 addi r6,r6,1 - addic. r5,r5,-1 - bne 71b -72: srwi. r7,r5,2 - beq 73f - mtctr r7 -74: stwu r0,4(r6) - bdnz 74b -73: andi. r5,r5,3 - beq 76f - mtctr r5 - addi r6,r6,3 -75: stbu r0,1(r6) - bdnz 75b -76: blr -/* here on a write fault in the initial single-byte copy */ -80: mfctr r3 - add r3,r3,r5 - blr -/* here on a write fault in the final single-byte copy */ -81: mfctr r3 + bdnz 40b +65: li r3,0 blr +/* read fault, initial single-byte copy */ +100: li r4,0 + b 90f +/* write fault, initial single-byte copy */ +101: li r4,1 +90: subf r5,r8,r5 + li r3,0 + b 99f +/* read fault, initial word copy */ +102: li r4,0 + b 91f +/* write fault, initial word copy */ +103: li r4,1 +91: li r3,2 + b 99f +/* read fault in 2nd half of cacheline loop */ +106: addi r5,r5,-16 +/* read fault in 1st half of cacheline loop */ +104: li r4,0 + b 92f +/* write fault in 2nd half of cacheline loop */ +107: addi r5,r5,-16 +/* fault on dcbz (effectively a write fault) */ +/* or write fault in 1st half of cacheline loop */ +105: li r4,1 +92: li r3,LG_CACHELINE_BYTES + b 99f +/* read fault in final word loop */ +108: li r4,0 + b 93f +/* write fault in final word loop */ +109: li r4,1 +93: andi. r5,r5,3 + li r3,2 + b 99f +/* read fault in final byte loop */ +110: li r4,0 + b 94f +/* write fault in final byte loop */ +111: li r4,1 +94: li r5,0 + li r3,0 +/* + * At this stage the number of bytes not copied is + * r5 + (ctr << r3), and r4 is 0 for read or 1 for write. + */ +99: mfctr r0 + slw r3,r0,r3 + add r3,r3,r5 + cmpwi 0,r4,0 + bne 120f +/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */ + srwi. r0,r3,2 + li r9,0 + mtctr r0 + beq 113f +112: stwu r9,4(r6) + bdnz 112b +113: andi. r0,r3,3 + mtctr r0 + beq 120f +114: stb r9,4(r6) + addi r6,r6,1 + bdnz 114b +120: blr + .section __ex_table,"a" .align 2 - .long 1b,98b - .long 11b,98b - .long 12b,88b - .long 13b,88b - .long 14b,3b - .long 15b,96b - .long 4b,99b - .long 16b,81b - .long 6b,90b - .long 17b,80b - .long 77b,76b - .long 74b,76b - .long 75b,76b + .long 70b,100b + .long 71b,101b + .long 72b,102b + .long 73b,103b + .long 53b,105b + .long 10b,104b + .long 11b,104b + .long 12b,104b + .long 13b,104b + .long 14b,105b + .long 15b,105b + .long 16b,105b + .long 17b,105b + .long 20b,106b + .long 21b,106b + .long 22b,106b + .long 23b,106b + .long 24b,107b + .long 25b,107b + .long 26b,107b + .long 27b,107b + .long 30b,108b + .long 31b,109b + .long 40b,110b + .long 41b,111b + .long 112b,120b + .long 114b,120b .text .globl __clear_user @@ -334,7 +530,6 @@ __clear_user: andi. r0,r6,3 add r4,r0,r4 subf r6,r0,r6 - /*rlwinm r0,r4,32-2,2,31*/ srwi r0,r4,2 mtctr r0 bdz 6f diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 216527e34..25d728fdd 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1107,7 +1107,7 @@ unsigned long __init find_available_memory(void) */ void __init paging_init(void) { - unsigned int zones_size[MAX_NR_ZONES], i; + unsigned long zones_size[MAX_NR_ZONES], i; /* * Grab some memory for bad_page and bad_pagetable to use. @@ -1197,7 +1197,7 @@ unsigned long __init *pmac_find_end_of_memory(void) unsigned long a, total; /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (64<<20) +#define RAM_LIMIT (768<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index f25060c94..8e924699f 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -115,42 +115,41 @@ extern void pmu_poll(void); int xmon_write(void *handle, void *ptr, int nb) { - char *p = ptr; - int i, c, ct; + char *p = ptr; + int i, c, ct; #ifdef CONFIG_BOOTX_TEXT - if (use_screen) { - /* write it on the screen */ - for (i = 0; i < nb; ++i) - drawchar(*p++); - return nb; - } + if (use_screen) { + /* write it on the screen */ + for (i = 0; i < nb; ++i) + drawchar(*p++); + return nb; + } #endif - if (!scc_initialized) - xmon_init_scc(); - for (i = 0; i < nb; ++i) { - ct = 0; - while ((*sccc & TXRDY) == 0) + if (!scc_initialized) + xmon_init_scc(); + ct = 0; + for (i = 0; i < nb; ++i) { + while ((*sccc & TXRDY) == 0) { #ifdef CONFIG_ADB - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#else - ; + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll(); #endif /* CONFIG_ADB */ - c = p[i]; - if (c == '\n' && !ct) { - c = '\r'; - ct = 1; - --i; - } else { - if (console) - printk("%c", c); - ct = 0; + } + c = p[i]; + if (c == '\n' && !ct) { + c = '\r'; + ct = 1; + --i; + } else { + if (console) + printk("%c", c); + ct = 0; + } + buf_access(); + *sccd = c; } - buf_access(); - *sccd = c; - } - return i; + return i; } int xmon_wants_key; @@ -285,7 +284,7 @@ xmon_init_scc() { int i, x; - if (macio_node != 0) { + if (via_modem && macio_node != 0) { unsigned int t0; feature_set(macio_node, FEATURE_Modem_power); diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 6db042563..7589958c8 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -259,18 +259,17 @@ CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m # CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 336ae208f..8c8903d26 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.31 2000/02/06 22:55:32 zaitcev Exp $ +/* $Id: ioport.c,v 1.34 2000/02/18 13:48:48 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -44,7 +44,6 @@ #include <asm/pgtable.h> struct resource *_sparc_find_resource(struct resource *r, unsigned long); -int _sparc_len2order(unsigned long len); static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, @@ -280,7 +279,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) return NULL; } - order = _sparc_len2order(len_total); + order = get_order(len_total); va = __get_free_pages(GFP_KERNEL, order); if (va == 0) { /* @@ -341,7 +340,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) pgp = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); mmu_unmap_dma_area(ba, n); - free_pages(pgp, _sparc_len2order(n)); + free_pages(pgp, get_order(n)); } /* @@ -349,7 +348,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) * CPU view of this memory may be inconsistent with * a device view and explicit flushing is necessary. */ -u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len) +u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len, int direction) { #if 0 /* This is the version that abuses consistent space */ unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; @@ -396,7 +395,7 @@ u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len) #endif } -void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) +void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n, int direction) { #if 0 /* This is the version that abuses consistent space */ struct resource *res; @@ -425,7 +424,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) #endif } -int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { mmu_get_scsi_sgl(sg, n, sdev->bus); @@ -436,14 +435,14 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) return n; } -void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { mmu_release_scsi_sgl(sg, n, sdev->bus); } /* */ -void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size) +void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size, int direction) { unsigned long va; struct resource *res; @@ -457,7 +456,7 @@ void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size) mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); } -void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { printk("sbus_dma_sync_sg: not implemented yet\n"); } @@ -482,7 +481,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) return NULL; } - order = _sparc_len2order(len_total); + order = get_order(len_total); va = __get_free_pages(GFP_KERNEL, order); if (va == 0) { printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT); @@ -562,14 +561,14 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) { int x; for (x = 0; x < n; x += PAGE_SIZE) { - (*_sparc_unmapioaddr)(p + n); + (*_sparc_unmapioaddr)((unsigned long)p + n); } } release_resource(res); kfree(res); - free_pages(pgp, _sparc_len2order(n)); + free_pages(pgp, get_order(n)); } /* Map a single buffer of the indicated size for DMA in streaming mode. @@ -578,8 +577,10 @@ void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size) +dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return virt_to_bus(ptr); } @@ -590,8 +591,10 @@ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size) * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) +void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do... */ } @@ -610,9 +613,13 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { int n; + + if (direction == PCI_DMA_NONE) + BUG(); + for (n = 0; n < nents; n++) { sg->dvma_address = virt_to_bus(sg->address); sg->dvma_length = sg->length; @@ -625,8 +632,10 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents) +void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do... */ } @@ -639,8 +648,10 @@ void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents) * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size) +void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); mmu_inval_dma_area((unsigned long)bus_to_virt(ba), (size + PAGE_SIZE-1) & PAGE_MASK); } @@ -651,8 +662,10 @@ void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size) * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); while (nents) { --nents; mmu_inval_dma_area((unsigned long)sg->address, @@ -739,19 +752,6 @@ _sparc_find_resource(struct resource *root, unsigned long hit) return NULL; } -int -_sparc_len2order(unsigned long len) -{ - int order; - - for (order = 0; order < 7; order++) /* 2^6 pages == 256K */ - if ((1 << (order + PAGE_SHIFT)) >= len) - return order; - printk("len2order: from %p: len %lu(0x%lx) yields order >=7.\n", - __builtin_return_address(0), len, len); - return 1; -} - /* * Necessary boot time initializations. */ diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index b504e2412..335eba208 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.12 2000/01/22 07:35:25 zaitcev Exp $ +/* $Id: pcic.c,v 1.13 2000/02/12 03:05:37 zaitcev Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -784,6 +784,7 @@ void __init pci_time_init(void) static __inline__ unsigned long do_gettimeoffset(void) { + struct tasklet_struct *t; unsigned long offset = 0; /* @@ -794,7 +795,8 @@ static __inline__ unsigned long do_gettimeoffset(void) readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); - if(test_bit(TIMER_BH, &bh_active)) + t = &bh_task_vec[TIMER_BH]; + if (test_bit(TASKLET_STATE_SCHED, &t->state)) offset = 1000000; return offset + count; } diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index d1b3eca63..cdc1f0751 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.89 2000/02/09 11:15:03 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.91 2000/02/18 20:23:24 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -145,11 +145,8 @@ EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(global_irq_lock); EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(global_bh_count); -EXPORT_SYMBOL(sparc_bh_lock); EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(synchronize_bh); #endif EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); @@ -193,6 +190,8 @@ EXPORT_SYMBOL(sbus_map_sg); EXPORT_SYMBOL(sbus_unmap_sg); EXPORT_SYMBOL(sbus_dma_sync_single); EXPORT_SYMBOL(sbus_dma_sync_sg); +EXPORT_SYMBOL(sbus_iounmap); +EXPORT_SYMBOL(sbus_ioremap); #endif #if CONFIG_PCI /* We do not have modular drivers for PCI devices yet. */ diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index fde9bccfd..5beb3adf0 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.60 2000/02/08 20:24:18 davem Exp $ +/* $Id: sys_sparc.c,v 1.61 2000/02/16 07:31:29 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -34,12 +34,39 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */ } +unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +{ + struct vm_area_struct * vmm; + + /* See asm-sparc/uaccess.h */ + if (len > TASK_SIZE - PAGE_SIZE) + return 0; + if (ARCH_SUN4C_SUN4 && len > 0x20000000) + return 0; + if (!addr) + addr = TASK_UNMAPPED_BASE; + addr = PAGE_ALIGN(addr); + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) { + addr = PAGE_OFFSET; + vmm = find_vma(current->mm, PAGE_OFFSET); + } + if (TASK_SIZE - PAGE_SIZE - len < addr) + return 0; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + } +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { if(ARCH_SUN4C_SUN4) { - if(brk >= 0x20000000 && brk < 0xe0000000) + if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) return current->mm->brk; } return sys_brk(brk); @@ -190,24 +217,16 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len, down(¤t->mm->mmap_sem); lock_kernel(); - retval = -ENOMEM; + retval = -EINVAL; len = PAGE_ALIGN(len); - if(!(flags & MAP_FIXED) && - (!addr || (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)))) { - addr = get_unmapped_area(0, len); - if(!addr) - goto out_putf; - if (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)) { - retval = -EINVAL; - goto out_putf; - } - } + if (ARCH_SUN4C_SUN4 && + (len > 0x20000000 || + ((flags & MAP_FIXED) && + addr < 0xe0000000 && addr + len > 0x20000000))) + goto out_putf; /* See asm-sparc/uaccess.h */ - retval = -EINVAL; - if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) + if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE) goto out_putf; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); @@ -238,6 +257,50 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); } +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sparc_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr) +{ + unsigned long ret = -EINVAL; + if (ARCH_SUN4C_SUN4) { + if (old_len > 0x20000000 || new_len > 0x20000000) + goto out; + if (addr < 0xe0000000 && addr + old_len > 0x20000000) + goto out; + } + if (old_len > TASK_SIZE - PAGE_SIZE || + new_len > TASK_SIZE - PAGE_SIZE) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (ARCH_SUN4C_SUN4 && + new_addr < 0xe0000000 && + new_addr + new_len > 0x20000000) + goto out_sem; + if (new_addr + new_len > TASK_SIZE - PAGE_SIZE) + goto out_sem; + } else if ((ARCH_SUN4C_SUN4 && addr < 0xe0000000 && + addr + new_len > 0x20000000) || + addr + new_len > TASK_SIZE - PAGE_SIZE) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} + /* we come to here via sys_nis_syscall so it can setup the regs argument */ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index bb3a5ad36..82b5ac653 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.112 2000/01/29 07:40:11 davem Exp $ +/* $Id: sys_sunos.c,v 1.113 2000/02/16 07:31:29 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -71,8 +71,10 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { - printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", - current->comm); + static int cnt; + if (cnt++ < 10) + printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", + current->comm); flags &= ~MAP_NORESERVE; } retval = -EBADF; @@ -84,19 +86,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, goto out; } - retval = -ENOMEM; - if(!(flags & MAP_FIXED) && - (!addr || (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)))) { - addr = get_unmapped_area(0, len); - if(!addr) - goto out_putf; - if (ARCH_SUN4C_SUN4 && - (addr >= 0x20000000 && addr < 0xe0000000)) { - retval = -EINVAL; - goto out_putf; - } - } + retval = -EINVAL; /* If this is ld.so or a shared library doing an mmap * of /dev/zero, transform it into an anonymous mapping. * SunOS is so stupid some times... hmph! @@ -105,18 +95,27 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR && MINOR(file->f_dentry->d_inode->i_rdev) == 5) { flags |= MAP_ANONYMOUS; + fput(file); file = 0; } } - if(!(flags & MAP_FIXED)) - addr = 0; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; - /* See asm-sparc/uaccess.h */ - retval = -EINVAL; - if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE))) - goto out_putf; + if(!(flags & MAP_FIXED)) + addr = 0; + else { + if (ARCH_SUN4C_SUN4 && + (len > 0x20000000 || + ((flags & MAP_FIXED) && + addr < 0xe0000000 && addr + len > 0x20000000))) + goto out_putf; + + /* See asm-sparc/uaccess.h */ + if (len > TASK_SIZE - PAGE_SIZE || + addr + len > TASK_SIZE - PAGE_SIZE) + goto out_putf; + } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 174522d03..8746958d7 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.93 2000/01/29 16:41:18 jj Exp $ +/* $Id: systbls.S,v 1.94 2000/02/16 07:31:30 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -69,7 +69,7 @@ sys_call_table: /*235*/ .long sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_nis_syscall, sys_nis_syscall #ifdef CONFIG_SUNOS_EMUL diff --git a/arch/sparc/lib/rwsem.S b/arch/sparc/lib/rwsem.S index 0d5f74139..0396bf2bc 100644 --- a/arch/sparc/lib/rwsem.S +++ b/arch/sparc/lib/rwsem.S @@ -1,4 +1,4 @@ -/* $Id: rwsem.S,v 1.2 2000/01/05 01:00:38 davem Exp $ +/* $Id: rwsem.S,v 1.4 2000/02/13 07:59:39 anton Exp $ * Assembly part of rw semaphores. * * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) @@ -26,16 +26,19 @@ ___down_read: tst %g7 bne 1b ld [%g1], %g7 - subcc %g7, 1, %g7 + sub %g7, 1, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - subcc %g7, 1, %g7 + sub %g7, 1, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr + add %g7, 1, %g7 nop + nop + subcc %g7, 1, %g7 bneg 3f nop 2: jmpl %o7, %g0 @@ -74,16 +77,19 @@ ___down_write: tst %g7 bne 1b ld [%g1], %g7 - subcc %g7, %g2, %g7 + sub %g7, %g2, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - subcc %g7, %g2, %g7 + sub %g7, %g2, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr + add %g7, %g2, %g7 + nop nop + subcc %g7, %g2, %g7 bne 3f nop 2: jmpl %o7, %g0 @@ -122,16 +128,19 @@ ___up_read: tst %g7 bne 1b ld [%g1], %g7 - addcc %g7, 1, %g7 + add %g7, 1, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - addcc %g7, 1, %g7 + add %g7, 1, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr nop + nop + nop + cmp %g7, 0 be 3f nop 2: jmpl %o7, %g0 @@ -164,16 +173,19 @@ ___up_write: tst %g7 bne 1b ld [%g1], %g7 - addcc %g7, %g2, %g7 + add %g7, %g2, %g7 st %g7, [%g1] stb %g0, [%g1 + 4] #else ld [%g1], %g7 - addcc %g7, %g2, %g7 + add %g7, %g2, %g7 st %g7, [%g1] #endif wr %g3, 0, %psr + sub %g7, %g2, %g7 + nop nop + addcc %g7, %g2, %g7 bcs 3f nop 2: jmpl %o7, %g0 diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index d9981e68b..909c46447 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.113 2000/01/21 11:38:47 jj Exp $ +/* $Id: fault.c,v 1.114 2000/02/14 04:52:36 jj Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -342,7 +342,6 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, { extern void sun4c_update_mmu_cache(struct vm_area_struct *, unsigned long,pte_t); - extern pgd_t *sun4c_pgd_offset(struct mm_struct *,unsigned long); extern pte_t *sun4c_pte_offset(pmd_t *,unsigned long); struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; @@ -362,7 +361,7 @@ asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, } } - pgdp = sun4c_pgd_offset(mm, address); + pgdp = pgd_offset(mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); if (pgd_val(*pgdp)) { diff --git a/arch/sparc/mm/nosun4c.c b/arch/sparc/mm/nosun4c.c index 05aa87b98..8ed9dcf00 100644 --- a/arch/sparc/mm/nosun4c.c +++ b/arch/sparc/mm/nosun4c.c @@ -1,4 +1,4 @@ -/* $Id: nosun4c.c,v 1.2 1999/08/31 06:54:36 davem Exp $ +/* $Id: nosun4c.c,v 1.3 2000/02/14 04:52:36 jj Exp $ * nosun4c.c: This file is a bunch of dummies for SMP compiles, * so that it does not need sun4c and avoid ifdefs. * @@ -52,11 +52,6 @@ void sun4c_complete_all_stores(void) { } -pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) -{ - return NULL; -} - pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address) { return NULL; diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index d46b45378..96aee65d6 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.206 2000/02/08 07:45:59 davem Exp $ +/* $Id: srmmu.c,v 1.208 2000/02/14 04:52:33 jj Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -201,7 +201,7 @@ static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot) } /* to find an entry in a top-level page table... */ -static inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) +extern inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + (address >> SRMMU_PGDIR_SHIFT); } @@ -1366,7 +1366,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) { struct vm_area_struct *vmaring; struct file *file; - struct inode *inode; + struct address_space *mapping; unsigned long flags, offset, vaddr, start; int alias_found = 0; pgd_t *pgdp; @@ -1378,10 +1378,10 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, file = vma->vm_file; if (!file) goto done; - inode = file->f_dentry->d_inode; + mapping = file->f_dentry->d_inode->i_mapping; offset = (address & PAGE_MASK) - vma->vm_start; - spin_lock(&inode->i_shared_lock); - vmaring = inode->i_mmap; + spin_lock(&mapping->i_shared_lock); + vmaring = mapping->i_mmap; do { /* Do not mistake ourselves as another mapping. */ if(vmaring == vma) @@ -1414,7 +1414,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, } } } while ((vmaring = vmaring->vm_next_share) != NULL); - spin_unlock(&inode->i_shared_lock); + spin_unlock(&mapping->i_shared_lock); if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) { pgdp = srmmu_pgd_offset(vma->vm_mm, address); @@ -2337,7 +2337,6 @@ void __init ld_mmu_srmmu(void) BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM); BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK); - BTFIXUPSET_CALL(pgd_offset, srmmu_pgd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_offset, srmmu_pte_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_free_kernel, srmmu_pte_free, BTFIXUPCALL_NORM); diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 715bdb864..6e93111ae 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.187 2000/02/08 07:46:01 davem Exp $ +/* $Id: sun4c.c,v 1.190 2000/02/14 04:52:34 jj Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -591,7 +591,7 @@ static unsigned long sun4c_translate_dvma(unsigned long busa) return (pte << PAGE_SHIFT) + PAGE_OFFSET; } -static unsigned long sun4c_unmap_dma_area(unsigned long busa, int len) +static void sun4c_unmap_dma_area(unsigned long busa, int len) { /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ /* XXX Implement this */ @@ -2185,7 +2185,7 @@ static unsigned long sun4c_pgd_page(pgd_t pgd) } /* to find an entry in a page-table-directory */ -pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) +extern inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + (address >> SUN4C_PGDIR_SHIFT); } @@ -2273,7 +2273,7 @@ extern __inline__ pgd_t *sun4c_get_pgd_fast(void) ret = (unsigned long *)__get_free_page(GFP_KERNEL); memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t)); - init = pgd_offset(&init_mm, 0); + init = sun4c_pgd_offset(&init_mm, 0); memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } @@ -2418,11 +2418,12 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr if(dentry) inode = dentry->d_inode; if(inode) { + struct address_space *mapping = inode->i_mapping; unsigned long offset = (address & PAGE_MASK) - vma->vm_start; struct vm_area_struct *vmaring; int alias_found = 0; - spin_lock(&inode->i_shared_lock); - vmaring = inode->i_mmap; + spin_lock(&mapping->i_shared_lock); + vmaring = mapping->i_mmap; do { unsigned long vaddr = vmaring->vm_start + offset; unsigned long start; @@ -2453,7 +2454,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr } } } while ((vmaring = vmaring->vm_next_share) != NULL); - spin_unlock(&inode->i_shared_lock); + spin_unlock(&mapping->i_shared_lock); if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); @@ -2695,7 +2696,6 @@ void __init ld_mmu_sun4c(void) BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM); BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK); - BTFIXUPSET_CALL(pgd_offset, sun4c_pgd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_offset, sun4c_pte_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_free_kernel, sun4c_pte_free_kernel, BTFIXUPCALL_NORM); diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S index e9fe43293..914f3071d 100644 --- a/arch/sparc/mm/swift.S +++ b/arch/sparc/mm/swift.S @@ -1,4 +1,4 @@ -/* $Id: swift.S,v 1.3 1999/11/14 06:13:56 zaitcev Exp $ +/* $Id: swift.S,v 1.4 2000/02/12 03:08:47 zaitcev Exp $ * swift.S: MicroSparc-II mmu/cache operations. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -41,10 +41,10 @@ swift_flush_chunk: swift_flush_page_to_ram: sethi %hi(0x2000), %o0 1: subcc %o0, 0x10, %o0 - sta %g0, [%o0] ASI_M_TXTC_TAG + add %o0, %o0, %o1 sta %g0, [%o0] ASI_M_DATAC_TAG bne 1b - nop + sta %g0, [%o1] ASI_M_TXTC_TAG retl nop #else diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index 6aebbfcc8..bee2a5574 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -226,9 +226,9 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX - tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'RealTek RTL-8139 support' CONFIG_8139TOO tristate 'PCI NE2000 support' CONFIG_NE2K_PCI - tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100 tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi endmenu diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 747ded255..917bb5e74 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -318,12 +318,12 @@ CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 04a5b6f7f..39a000ef3 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,7 +1,7 @@ -/* $Id: ioctl32.c,v 1.79 2000/02/08 20:24:25 davem Exp $ +/* $Id: ioctl32.c,v 1.80 2000/02/17 06:45:09 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * * These routines maintain argument size conversion between 32bit and 64bit @@ -42,6 +42,7 @@ #include <linux/netdevice.h> #include <linux/raw.h> #include <linux/smb_fs.h> +#include <linux/blkpg.h> #include <scsi/scsi.h> /* Ugly hack. */ @@ -435,7 +436,7 @@ struct ifconf32 { __kernel_caddr_t32 ifcbuf; }; -static int dev_ifname32(unsigned int fd, unsigned long arg) +static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) { struct net_device *dev; struct ifreq32 ifr32; @@ -454,7 +455,7 @@ static int dev_ifname32(unsigned int fd, unsigned long arg) return (err ? -EFAULT : 0); } -static inline int dev_ifconf(unsigned int fd, unsigned long arg) +static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifconf32 ifc32; struct ifconf ifc; @@ -671,7 +672,7 @@ struct hd_geometry32 { u32 start; }; -static inline int hdio_getgeo(unsigned int fd, unsigned long arg) +static inline int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct hd_geometry geo; @@ -1024,8 +1025,8 @@ struct floppy_write_errors32 { unsigned int badness; }; -#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) -#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) +#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) +#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) #define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) #define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) #define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) @@ -1648,7 +1649,7 @@ struct consolefontdesc32 { u32 chardata; /* font data in expanded form */ }; -static int do_fontx_ioctl(struct file *file, int cmd, struct consolefontdesc32 *user_cfd) +static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { struct consolefontdesc cfdarg; struct console_font_op op; @@ -1657,7 +1658,7 @@ static int do_fontx_ioctl(struct file *file, int cmd, struct consolefontdesc32 * perm = vt_check(file); if (perm < 0) return perm; - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) return -EFAULT; cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata); @@ -1703,7 +1704,7 @@ struct console_font_op32 { u32 data; /* font data with height fixed to 32 */ }; -static int do_kdfontop_ioctl(struct file *file, struct console_font_op32 *fontop) +static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { struct console_font_op op; int perm = vt_check(file), i; @@ -1731,7 +1732,7 @@ struct unimapdesc32 { u32 entries; }; -static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user_ud) +static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) { struct unimapdesc32 tmp; int perm = vt_check(file); @@ -1978,768 +1979,813 @@ static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) return -EINVAL; } -asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct file * filp; - int error = -EBADF; + return -EINVAL; +} - lock_kernel(); - filp = fget(fd); - if(!filp) - goto out2; +static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* The mkswap binary hard codes it to Intel value :-((( */ + return w_long(fd, BLKGETSIZE, arg); +} - if (!filp->f_op || !filp->f_op->ioctl) { - error = sys_ioctl (fd, cmd, arg); - goto out; - } - switch (cmd) { - case SIOCGIFNAME: - error = dev_ifname32(fd, arg); - goto out; +struct blkpg_ioctl_arg32 { + int op; + int flags; + int datalen; + u32 data; +}; + +static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + int err; + mm_segment_t old_fs = get_fs(); + + err = get_user(a.op, &arg->op); + err |= __get_user(a.flags, &arg->flags); + err |= __get_user(a.datalen, &arg->datalen); + err |= __get_user((long)a.data, &arg->data); + if (err) return err; + switch (a.op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + if (a.datalen < sizeof(struct blkpg_partition)) + return -EINVAL; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + a.data = &p; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&a); + set_fs (old_fs); + default: + return -EINVAL; + } + return err; +} - case SIOCGIFCONF: - error = dev_ifconf(fd, arg); - goto out; - - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - case SIOCGIFMTU: - case SIOCSIFMTU: - case SIOCGIFMEM: - case SIOCSIFMEM: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCGIFINDEX: - case SIOCGIFMAP: - case SIOCSIFMAP: - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: - case SIOCGPPPSTATS: - case SIOCGPPPCSTATS: - case SIOCGPPPVER: - case SIOCGIFTXQLEN: - case SIOCSIFTXQLEN: - case SIOCETHTOOL: - error = dev_ifsioc(fd, cmd, arg); - goto out; - - case SIOCADDRT: - case SIOCDELRT: - error = routing_ioctl(fd, cmd, arg); - goto out; +static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); +} - case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and - * the user would have seen just an -EINVAL anyways. - */ - error = -EINVAL; - goto out; +struct ioctl_trans { + unsigned int cmd; + unsigned int handler; + unsigned int next; +}; - case SIOCGSTAMP: - /* Sorry, timeval in the kernel is different now. */ - error = do_siocgstamp(fd, cmd, arg); - goto out; +#define COMPATIBLE_IOCTL(cmd) asm volatile(".word %0, sys_ioctl, 0" : : "i" (cmd)); +#define HANDLE_IOCTL(cmd,handler) asm volatile(".word %0, %1, 0" : : "i" (cmd), "i" (handler)); +#define IOCTL_TABLE_START void ioctl32_foo(void) { asm volatile(".data\nioctl_translations:"); +#define IOCTL_TABLE_END asm volatile("\nioctl_translations_end:\n\t.previous"); } - case HDIO_GETGEO: - error = hdio_getgeo(fd, arg); - goto out; - - case BLKRAGET: - case BLKGETSIZE: - case 0x1260: - /* The mkswap binary hard codes it to Intel value :-((( */ - if(cmd == 0x1260) - cmd = BLKGETSIZE; - error = w_long(fd, cmd, arg); - goto out; - - case FBIOPUTCMAP32: - case FBIOGETCMAP32: - error = fbiogetputcmap(fd, cmd, arg); - goto out; - - case FBIOSCURSOR32: - error = fbiogscursor(fd, cmd, arg); - goto out; +IOCTL_TABLE_START +/* List here exlicitly which ioctl's are known to have + * compatable types passed or none at all... + */ +/* Big T */ +COMPATIBLE_IOCTL(TCGETA) +COMPATIBLE_IOCTL(TCSETA) +COMPATIBLE_IOCTL(TCSETAW) +COMPATIBLE_IOCTL(TCSETAF) +COMPATIBLE_IOCTL(TCSBRK) +COMPATIBLE_IOCTL(TCXONC) +COMPATIBLE_IOCTL(TCFLSH) +COMPATIBLE_IOCTL(TCGETS) +COMPATIBLE_IOCTL(TCSETS) +COMPATIBLE_IOCTL(TCSETSW) +COMPATIBLE_IOCTL(TCSETSF) +COMPATIBLE_IOCTL(TIOCLINUX) +/* Little t */ +COMPATIBLE_IOCTL(TIOCGETD) +COMPATIBLE_IOCTL(TIOCSETD) +COMPATIBLE_IOCTL(TIOCEXCL) +COMPATIBLE_IOCTL(TIOCNXCL) +COMPATIBLE_IOCTL(TIOCCONS) +COMPATIBLE_IOCTL(TIOCGSOFTCAR) +COMPATIBLE_IOCTL(TIOCSSOFTCAR) +COMPATIBLE_IOCTL(TIOCSWINSZ) +COMPATIBLE_IOCTL(TIOCGWINSZ) +COMPATIBLE_IOCTL(TIOCMGET) +COMPATIBLE_IOCTL(TIOCMBIC) +COMPATIBLE_IOCTL(TIOCMBIS) +COMPATIBLE_IOCTL(TIOCMSET) +COMPATIBLE_IOCTL(TIOCPKT) +COMPATIBLE_IOCTL(TIOCNOTTY) +COMPATIBLE_IOCTL(TIOCSTI) +COMPATIBLE_IOCTL(TIOCOUTQ) +COMPATIBLE_IOCTL(TIOCSPGRP) +COMPATIBLE_IOCTL(TIOCGPGRP) +COMPATIBLE_IOCTL(TIOCSCTTY) +COMPATIBLE_IOCTL(TIOCGPTN) +COMPATIBLE_IOCTL(TIOCSPTLCK) +COMPATIBLE_IOCTL(TIOCGSERIAL) +COMPATIBLE_IOCTL(TIOCSSERIAL) +COMPATIBLE_IOCTL(TIOCSERGETLSR) +/* Big F */ +COMPATIBLE_IOCTL(FBIOGTYPE) +COMPATIBLE_IOCTL(FBIOSATTR) +COMPATIBLE_IOCTL(FBIOGATTR) +COMPATIBLE_IOCTL(FBIOSVIDEO) +COMPATIBLE_IOCTL(FBIOGVIDEO) +COMPATIBLE_IOCTL(FBIOGCURSOR32) /* This is not implemented yet. Later it should be converted... */ +COMPATIBLE_IOCTL(FBIOSCURPOS) +COMPATIBLE_IOCTL(FBIOGCURPOS) +COMPATIBLE_IOCTL(FBIOGCURMAX) +COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO) +COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO) +COMPATIBLE_IOCTL(FBIOPAN_DISPLAY) +COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO) +COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO) +COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO) +COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE) +COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE) +COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP) +COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP) +/* Little f */ +COMPATIBLE_IOCTL(FIOCLEX) +COMPATIBLE_IOCTL(FIONCLEX) +COMPATIBLE_IOCTL(FIOASYNC) +COMPATIBLE_IOCTL(FIONBIO) +COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ +/* 0x00 */ +COMPATIBLE_IOCTL(FIBMAP) +COMPATIBLE_IOCTL(FIGETBSZ) +/* 0x03 -- HD/IDE ioctl's used by hdparm and friends. + * Some need translations, these do not. + */ +COMPATIBLE_IOCTL(HDIO_GET_IDENTITY) +COMPATIBLE_IOCTL(HDIO_SET_DMA) +COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS) +COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR) +COMPATIBLE_IOCTL(HDIO_SET_NOWERR) +COMPATIBLE_IOCTL(HDIO_SET_32BIT) +COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT) +COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) +COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE) +COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) +COMPATIBLE_IOCTL(HDIO_SET_NICE) +/* 0x02 -- Floppy ioctls */ +COMPATIBLE_IOCTL(FDMSGON) +COMPATIBLE_IOCTL(FDMSGOFF) +COMPATIBLE_IOCTL(FDSETEMSGTRESH) +COMPATIBLE_IOCTL(FDFLUSH) +COMPATIBLE_IOCTL(FDWERRORCLR) +COMPATIBLE_IOCTL(FDSETMAXERRS) +COMPATIBLE_IOCTL(FDGETMAXERRS) +COMPATIBLE_IOCTL(FDGETDRVTYP) +COMPATIBLE_IOCTL(FDEJECT) +COMPATIBLE_IOCTL(FDCLRPRM) +COMPATIBLE_IOCTL(FDFMTBEG) +COMPATIBLE_IOCTL(FDFMTEND) +COMPATIBLE_IOCTL(FDRESET) +COMPATIBLE_IOCTL(FDTWADDLE) +COMPATIBLE_IOCTL(FDFMTTRK) +COMPATIBLE_IOCTL(FDRAWCMD) +/* 0x12 */ +COMPATIBLE_IOCTL(BLKROSET) +COMPATIBLE_IOCTL(BLKROGET) +COMPATIBLE_IOCTL(BLKRRPART) +COMPATIBLE_IOCTL(BLKFLSBUF) +COMPATIBLE_IOCTL(BLKRASET) +COMPATIBLE_IOCTL(BLKFRASET) +COMPATIBLE_IOCTL(BLKSECTSET) +COMPATIBLE_IOCTL(BLKSSZGET) - case FBIOGET_FSCREENINFO: - case FBIOGETCMAP: - case FBIOPUTCMAP: - error = fb_ioctl_trans(fd, cmd, arg); - goto out; - case HDIO_GET_KEEPSETTINGS: - case HDIO_GET_UNMASKINTR: - case HDIO_GET_DMA: - case HDIO_GET_32BIT: - case HDIO_GET_MULTCOUNT: - case HDIO_GET_NOWERR: - case HDIO_GET_NICE: - error = hdio_ioctl_trans(fd, cmd, arg); - goto out; +#if 0 /* New RAID code is being merged, fix up to handle + * new RAID ioctls when fully merged in 2.3.x -DaveM + */ +/* 0x09 */ +COMPATIBLE_IOCTL(REGISTER_DEV) +COMPATIBLE_IOCTL(REGISTER_DEV_NEW) +COMPATIBLE_IOCTL(START_MD) +COMPATIBLE_IOCTL(STOP_MD) +#endif + +/* Big K */ +COMPATIBLE_IOCTL(PIO_FONT) +COMPATIBLE_IOCTL(GIO_FONT) +COMPATIBLE_IOCTL(KDSIGACCEPT) +COMPATIBLE_IOCTL(KDGETKEYCODE) +COMPATIBLE_IOCTL(KDSETKEYCODE) +COMPATIBLE_IOCTL(KIOCSOUND) +COMPATIBLE_IOCTL(KDMKTONE) +COMPATIBLE_IOCTL(KDGKBTYPE) +COMPATIBLE_IOCTL(KDSETMODE) +COMPATIBLE_IOCTL(KDGETMODE) +COMPATIBLE_IOCTL(KDSKBMODE) +COMPATIBLE_IOCTL(KDGKBMODE) +COMPATIBLE_IOCTL(KDSKBMETA) +COMPATIBLE_IOCTL(KDGKBMETA) +COMPATIBLE_IOCTL(KDGKBENT) +COMPATIBLE_IOCTL(KDSKBENT) +COMPATIBLE_IOCTL(KDGKBSENT) +COMPATIBLE_IOCTL(KDSKBSENT) +COMPATIBLE_IOCTL(KDGKBDIACR) +COMPATIBLE_IOCTL(KDSKBDIACR) +COMPATIBLE_IOCTL(KDGKBLED) +COMPATIBLE_IOCTL(KDSKBLED) +COMPATIBLE_IOCTL(KDGETLED) +COMPATIBLE_IOCTL(KDSETLED) +COMPATIBLE_IOCTL(GIO_SCRNMAP) +COMPATIBLE_IOCTL(PIO_SCRNMAP) +COMPATIBLE_IOCTL(GIO_UNISCRNMAP) +COMPATIBLE_IOCTL(PIO_UNISCRNMAP) +COMPATIBLE_IOCTL(PIO_FONTRESET) +COMPATIBLE_IOCTL(PIO_UNIMAPCLR) +/* Little k */ +COMPATIBLE_IOCTL(KIOCTYPE) +COMPATIBLE_IOCTL(KIOCLAYOUT) +COMPATIBLE_IOCTL(KIOCGTRANS) +COMPATIBLE_IOCTL(KIOCTRANS) +COMPATIBLE_IOCTL(KIOCCMD) +COMPATIBLE_IOCTL(KIOCSDIRECT) +COMPATIBLE_IOCTL(KIOCSLED) +COMPATIBLE_IOCTL(KIOCGLED) +COMPATIBLE_IOCTL(KIOCSRATE) +COMPATIBLE_IOCTL(KIOCGRATE) +/* Big S */ +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN) +COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK) +COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK) +COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY) +COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE) +COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE) +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER) +COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) +/* Big V */ +COMPATIBLE_IOCTL(VT_SETMODE) +COMPATIBLE_IOCTL(VT_GETMODE) +COMPATIBLE_IOCTL(VT_GETSTATE) +COMPATIBLE_IOCTL(VT_OPENQRY) +COMPATIBLE_IOCTL(VT_ACTIVATE) +COMPATIBLE_IOCTL(VT_WAITACTIVE) +COMPATIBLE_IOCTL(VT_RELDISP) +COMPATIBLE_IOCTL(VT_DISALLOCATE) +COMPATIBLE_IOCTL(VT_RESIZE) +COMPATIBLE_IOCTL(VT_RESIZEX) +COMPATIBLE_IOCTL(VT_LOCKSWITCH) +COMPATIBLE_IOCTL(VT_UNLOCKSWITCH) +/* Little v */ +COMPATIBLE_IOCTL(VUIDSFORMAT) +COMPATIBLE_IOCTL(VUIDGFORMAT) +/* Little v, the video4linux ioctls */ +COMPATIBLE_IOCTL(VIDIOCGCAP) +COMPATIBLE_IOCTL(VIDIOCGCHAN) +COMPATIBLE_IOCTL(VIDIOCSCHAN) +COMPATIBLE_IOCTL(VIDIOCGPICT) +COMPATIBLE_IOCTL(VIDIOCSPICT) +COMPATIBLE_IOCTL(VIDIOCCAPTURE) +COMPATIBLE_IOCTL(VIDIOCKEY) +COMPATIBLE_IOCTL(VIDIOCGAUDIO) +COMPATIBLE_IOCTL(VIDIOCSAUDIO) +COMPATIBLE_IOCTL(VIDIOCSYNC) +COMPATIBLE_IOCTL(VIDIOCMCAPTURE) +COMPATIBLE_IOCTL(VIDIOCGMBUF) +COMPATIBLE_IOCTL(VIDIOCGUNIT) +COMPATIBLE_IOCTL(VIDIOCGCAPTURE) +COMPATIBLE_IOCTL(VIDIOCSCAPTURE) +/* BTTV specific... */ +COMPATIBLE_IOCTL(_IOW('v', BASE_VIDIOCPRIVATE+0, char [256])) +COMPATIBLE_IOCTL(_IOR('v', BASE_VIDIOCPRIVATE+1, char [256])) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)) +COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */ +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int)) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int)) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)) +/* Little p (/dev/rtc, /dev/envctrl, etc.) */ +COMPATIBLE_IOCTL(RTCGET) +COMPATIBLE_IOCTL(RTCSET) +COMPATIBLE_IOCTL(I2CIOCSADR) +COMPATIBLE_IOCTL(I2CIOCGADR) +/* Little m */ +COMPATIBLE_IOCTL(MTIOCTOP) +/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have + * embedded pointers in the arg which we'd need to clean up... + */ +COMPATIBLE_IOCTL(OPROMGETOPT) +COMPATIBLE_IOCTL(OPROMSETOPT) +COMPATIBLE_IOCTL(OPROMNXTOPT) +COMPATIBLE_IOCTL(OPROMSETOPT2) +COMPATIBLE_IOCTL(OPROMNEXT) +COMPATIBLE_IOCTL(OPROMCHILD) +COMPATIBLE_IOCTL(OPROMGETPROP) +COMPATIBLE_IOCTL(OPROMNXTPROP) +COMPATIBLE_IOCTL(OPROMU2P) +COMPATIBLE_IOCTL(OPROMGETCONS) +COMPATIBLE_IOCTL(OPROMGETFBNAME) +COMPATIBLE_IOCTL(OPROMGETBOOTARGS) +COMPATIBLE_IOCTL(OPROMSETCUR) +COMPATIBLE_IOCTL(OPROMPCI2NODE) +COMPATIBLE_IOCTL(OPROMPATH2NODE) +/* Socket level stuff */ +COMPATIBLE_IOCTL(FIOSETOWN) +COMPATIBLE_IOCTL(SIOCSPGRP) +COMPATIBLE_IOCTL(FIOGETOWN) +COMPATIBLE_IOCTL(SIOCGPGRP) +COMPATIBLE_IOCTL(SIOCATMARK) +COMPATIBLE_IOCTL(SIOCSIFLINK) +COMPATIBLE_IOCTL(SIOCSIFENCAP) +COMPATIBLE_IOCTL(SIOCGIFENCAP) +COMPATIBLE_IOCTL(SIOCSIFBR) +COMPATIBLE_IOCTL(SIOCGIFBR) +COMPATIBLE_IOCTL(SIOCSARP) +COMPATIBLE_IOCTL(SIOCGARP) +COMPATIBLE_IOCTL(SIOCDARP) +#if 0 /* XXX No longer exist in new routing code. XXX */ +COMPATIBLE_IOCTL(OLD_SIOCSARP) +COMPATIBLE_IOCTL(OLD_SIOCGARP) +COMPATIBLE_IOCTL(OLD_SIOCDARP) +#endif +COMPATIBLE_IOCTL(SIOCSRARP) +COMPATIBLE_IOCTL(SIOCGRARP) +COMPATIBLE_IOCTL(SIOCDRARP) +COMPATIBLE_IOCTL(SIOCADDDLCI) +COMPATIBLE_IOCTL(SIOCDELDLCI) +/* SG stuff */ +COMPATIBLE_IOCTL(SG_SET_TIMEOUT) +COMPATIBLE_IOCTL(SG_GET_TIMEOUT) +COMPATIBLE_IOCTL(SG_EMULATED_HOST) +COMPATIBLE_IOCTL(SG_SET_TRANSFORM) +COMPATIBLE_IOCTL(SG_GET_TRANSFORM) +/* PPP stuff */ +COMPATIBLE_IOCTL(PPPIOCGFLAGS) +COMPATIBLE_IOCTL(PPPIOCSFLAGS) +COMPATIBLE_IOCTL(PPPIOCGASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCSASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCGUNIT) +COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCGMRU) +COMPATIBLE_IOCTL(PPPIOCSMRU) +COMPATIBLE_IOCTL(PPPIOCSMAXCID) +COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCXFERUNIT) +COMPATIBLE_IOCTL(PPPIOCGNPMODE) +COMPATIBLE_IOCTL(PPPIOCSNPMODE) +COMPATIBLE_IOCTL(PPPIOCGDEBUG) +COMPATIBLE_IOCTL(PPPIOCSDEBUG) +COMPATIBLE_IOCTL(PPPIOCNEWUNIT) +COMPATIBLE_IOCTL(PPPIOCATTACH) +COMPATIBLE_IOCTL(PPPIOCDETACH) +/* CDROM stuff */ +COMPATIBLE_IOCTL(CDROMPAUSE) +COMPATIBLE_IOCTL(CDROMRESUME) +COMPATIBLE_IOCTL(CDROMPLAYMSF) +COMPATIBLE_IOCTL(CDROMPLAYTRKIND) +COMPATIBLE_IOCTL(CDROMREADTOCHDR) +COMPATIBLE_IOCTL(CDROMREADTOCENTRY) +COMPATIBLE_IOCTL(CDROMSTOP) +COMPATIBLE_IOCTL(CDROMSTART) +COMPATIBLE_IOCTL(CDROMEJECT) +COMPATIBLE_IOCTL(CDROMVOLCTRL) +COMPATIBLE_IOCTL(CDROMSUBCHNL) +COMPATIBLE_IOCTL(CDROMEJECT_SW) +COMPATIBLE_IOCTL(CDROMMULTISESSION) +COMPATIBLE_IOCTL(CDROM_GET_MCN) +COMPATIBLE_IOCTL(CDROMRESET) +COMPATIBLE_IOCTL(CDROMVOLREAD) +COMPATIBLE_IOCTL(CDROMSEEK) +COMPATIBLE_IOCTL(CDROMPLAYBLK) +COMPATIBLE_IOCTL(CDROMCLOSETRAY) +COMPATIBLE_IOCTL(CDROM_SET_OPTIONS) +COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS) +COMPATIBLE_IOCTL(CDROM_SELECT_SPEED) +COMPATIBLE_IOCTL(CDROM_SELECT_DISC) +COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED) +COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS) +COMPATIBLE_IOCTL(CDROM_DISC_STATUS) +COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS) +COMPATIBLE_IOCTL(CDROM_LOCKDOOR) +COMPATIBLE_IOCTL(CDROM_DEBUG) +COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY) +/* Big L */ +COMPATIBLE_IOCTL(LOOP_SET_FD) +COMPATIBLE_IOCTL(LOOP_CLR_FD) +/* Big A */ +COMPATIBLE_IOCTL(AUDIO_GETINFO) +COMPATIBLE_IOCTL(AUDIO_SETINFO) +COMPATIBLE_IOCTL(AUDIO_DRAIN) +COMPATIBLE_IOCTL(AUDIO_GETDEV) +COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS) +COMPATIBLE_IOCTL(AUDIO_FLUSH) +/* Big Q for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET) +COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO) +COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE) +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT) +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT) +COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE) +COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR) +COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI) +COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES) +COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS) +COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS) +COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO) +COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL) +COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE) +COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC) +COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND) +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE) +/* Big T for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE) +COMPATIBLE_IOCTL(SNDCTL_TMR_START) +COMPATIBLE_IOCTL(SNDCTL_TMR_STOP) +COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE) +COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO) +COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE) +COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME) +COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT) +/* Little m for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME) +COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE) +COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD) +/* Big P for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_DSP_RESET) +COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC) +COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED) +COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE) +COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS) +COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER) +COMPATIBLE_IOCTL(SNDCTL_DSP_POST) +COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE) +COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR) +/* SNDCTL_DSP_MAPINBUF, XXX needs translation */ +/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */ +COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY) +COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE) +COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE) +COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS) +COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS) +COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER) +/* Big C for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_COPR_RESET) +COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD) +COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA) +COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE) +COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA) +COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE) +COMPATIBLE_IOCTL(SNDCTL_COPR_RUN) +COMPATIBLE_IOCTL(SNDCTL_COPR_HALT) +COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG) +COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG) +/* Big M for sound/OSS */ +COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE) +/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */ +/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */ +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE) +/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */ +/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */ +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC) +COMPATIBLE_IOCTL(SOUND_MIXER_INFO) +COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO) +COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5) +COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) +COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) +COMPATIBLE_IOCTL(OSS_GETVERSION) +/* AUTOFS */ +COMPATIBLE_IOCTL(AUTOFS_IOC_READY) +COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL) +COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC) +COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) +COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) +/* Raw devices */ +COMPATIBLE_IOCTL(RAW_SETBIND) +COMPATIBLE_IOCTL(RAW_GETBIND) +/* SMB ioctls which do not need any translations */ +COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) +/* Little a */ +COMPATIBLE_IOCTL(ATMSIGD_CTRL) +COMPATIBLE_IOCTL(ATMARPD_CTRL) +COMPATIBLE_IOCTL(ATMLEC_CTRL) +COMPATIBLE_IOCTL(ATMLEC_MCAST) +COMPATIBLE_IOCTL(ATMLEC_DATA) +COMPATIBLE_IOCTL(ATM_SETSC) +COMPATIBLE_IOCTL(SIOCSIFATMTCP) +COMPATIBLE_IOCTL(SIOCMKCLIP) +COMPATIBLE_IOCTL(ATMARP_MKIP) +COMPATIBLE_IOCTL(ATMARP_SETENTRY) +COMPATIBLE_IOCTL(ATMARP_ENCAP) +COMPATIBLE_IOCTL(ATMTCP_CREATE) +COMPATIBLE_IOCTL(ATMTCP_REMOVE) +COMPATIBLE_IOCTL(ATMMPC_CTRL) +COMPATIBLE_IOCTL(ATMMPC_DATA) +/* And these ioctls need translation */ +HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) +HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) +HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc) +HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc) +HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCETHTOOL, dev_ifsioc) +HANDLE_IOCTL(SIOCADDRT, routing_ioctl) +HANDLE_IOCTL(SIOCDELRT, routing_ioctl) +/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ +HANDLE_IOCTL(SIOCRTMSG, ret_einval) +HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) +HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) +HANDLE_IOCTL(BLKRAGET, w_long) +HANDLE_IOCTL(BLKGETSIZE, w_long) +HANDLE_IOCTL(0x1260, broken_blkgetsize) +HANDLE_IOCTL(BLKFRAGET, w_long) +HANDLE_IOCTL(BLKSECTGET, w_long) +HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) +HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap) +HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap) +HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor) +HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans) +HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) +HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) +HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) +HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans) +HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans) +HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans) +HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) +HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) +HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) +HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) +HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl) +HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl) +HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) +HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) +HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) +HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) +/* One SMB ioctl needs translations. */ +#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32) +HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) +HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) +HANDLE_IOCTL(SUNI_GETLOOP, do_atm_ioctl) +HANDLE_IOCTL(SUNI_SETLOOP, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) +IOCTL_TABLE_END + +unsigned int ioctl32_hash_table[1024]; + +extern inline unsigned long ioctl32_hash(unsigned long cmd) +{ + return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff; +} - case FDSETPRM32: - case FDDEFPRM32: - case FDGETPRM32: - case FDSETDRVPRM32: - case FDGETDRVPRM32: - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - case FDGETFDCSTAT32: - case FDWERRORGET32: - error = fd_ioctl_trans(fd, cmd, arg); - goto out; +static void ioctl32_insert_translation(struct ioctl_trans *trans) +{ + unsigned long hash; + struct ioctl_trans *t; + + hash = ioctl32_hash (trans->cmd); + if (!ioctl32_hash_table[hash]) + ioctl32_hash_table[hash] = (u32)(long)trans; + else { + t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash]; + while (t->next) + t = (struct ioctl_trans *)(long)t->next; + trans->next = 0; + t->next = (u32)(long)trans; + } +} - case PPPIOCGIDLE32: - case PPPIOCSCOMPRESS32: - error = ppp_ioctl_trans(fd, cmd, arg); - goto out; +static int __init init_sys32_ioctl(void) +{ + int i; + extern struct ioctl_trans ioctl_translations[], ioctl_translations_end[]; - case MTIOCGET32: - case MTIOCPOS32: - case MTIOCGETCONFIG32: - case MTIOCSETCONFIG32: - error = mt_ioctl_trans(fd, cmd, arg); - goto out; + for (i = 0; &ioctl_translations[i] < &ioctl_translations_end[0]; i++) + ioctl32_insert_translation(&ioctl_translations[i]); + return 0; +} - case CDROMREADMODE2: - case CDROMREADMODE1: - case CDROMREADRAW: - case CDROMREADCOOKED: - case CDROMREADAUDIO: - case CDROMREADALL: - case CDROM_SEND_PACKET: - error = cdrom_ioctl_trans(fd, cmd, arg); - goto out; - - case LOOP_SET_STATUS: - case LOOP_GET_STATUS: - error = loop_status(fd, cmd, arg); - goto out; +__initcall(init_sys32_ioctl); -#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) - case AUTOFS_IOC_SETTIMEOUT32: - error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); - goto out; - - case PIO_FONTX: - case GIO_FONTX: - error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)arg); - goto out; - - case PIO_UNIMAP: - case GIO_UNIMAP: - error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)arg); - goto out; +static struct ioctl_trans *additional_ioctls; - case KDFONTOP: - error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg); - goto out; - - case EXT2_IOC32_GETFLAGS: - case EXT2_IOC32_SETFLAGS: - case EXT2_IOC32_GETVERSION: - case EXT2_IOC32_SETVERSION: - error = do_ext2_ioctl(fd, cmd, arg); - goto out; - - case VIDIOCGTUNER32: - case VIDIOCSTUNER32: - case VIDIOCGWIN32: - case VIDIOCSWIN32: - case VIDIOCGFBUF32: - case VIDIOCSFBUF32: - case VIDIOCGFREQ32: - case VIDIOCSFREQ32: - error = do_video_ioctl(fd, cmd, arg); - goto out; +/* Always call these with kernel lock held! */ - /* One SMB ioctl needs translations. */ - case _IOR('u', 1, __kernel_uid_t32): /* SMB_IOC_GETMOUNTUID */ - error = do_smb_getmountuid(fd, cmd, arg); - goto out; +int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)) +{ + int i; + if (!additional_ioctls) { + additional_ioctls = module_map(PAGE_SIZE); + if (!additional_ioctls) return -ENOMEM; + } + for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++) + if (!additional_ioctls[i].cmd) + break; + if (i == PAGE_SIZE/sizeof(struct ioctl_trans)) + return -ENOMEM; + additional_ioctls[i].cmd = cmd; + if (!handler) + additional_ioctls[i].handler = (u32)(long)sys_ioctl; + else + additional_ioctls[i].handler = (u32)(long)handler; + ioctl32_insert_translation(&additional_ioctls[i]); + return 0; +} - case ATM_GETLINKRATE32: - case ATM_GETNAMES32: - case ATM_GETTYPE32: - case ATM_GETESI32: - case ATM_GETADDR32: - case ATM_RSTADDR32: - case ATM_ADDADDR32: - case ATM_DELADDR32: - case ATM_GETCIRANGE32: - case ATM_SETCIRANGE32: - case ATM_SETESI32: - case ATM_SETESIF32: - case ATM_GETSTAT32: - case ATM_GETSTATZ32: - case SUNI_GETLOOP: - case SUNI_SETLOOP: - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - error = do_atm_ioctl(fd, cmd, arg); - goto out; - - /* List here exlicitly which ioctl's are known to have - * compatable types passed or none at all... - */ +int unregister_ioctl32_conversion(unsigned int cmd) +{ + unsigned long hash = ioctl32_hash(cmd); + struct ioctl_trans *t, *t1; + + t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash]; + if (!t) return -EINVAL; + if (t->cmd == cmd && t >= additional_ioctls && + (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + ioctl32_hash_table[hash] = t->next; + t->cmd = 0; + return 0; + } else while (t->next) { + t1 = (struct ioctl_trans *)(long)t->next; + if (t1->cmd == cmd && t1 >= additional_ioctls && + (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + t1->cmd = 0; + t->next = t1->next; + return 0; + } + t = t1; + } + return -EINVAL; +} - /* Big T */ - case TCGETA: - case TCSETA: - case TCSETAW: - case TCSETAF: - case TCSBRK: - case TCXONC: - case TCFLSH: - case TCGETS: - case TCSETS: - case TCSETSW: - case TCSETSF: - case TIOCLINUX: - - /* Little t */ - case TIOCGETD: - case TIOCSETD: - case TIOCEXCL: - case TIOCNXCL: - case TIOCCONS: - case TIOCGSOFTCAR: - case TIOCSSOFTCAR: - case TIOCSWINSZ: - case TIOCGWINSZ: - case TIOCMGET: - case TIOCMBIC: - case TIOCMBIS: - case TIOCMSET: - case TIOCPKT: - case TIOCNOTTY: - case TIOCSTI: - case TIOCOUTQ: - case TIOCSPGRP: - case TIOCGPGRP: - case TIOCSCTTY: - case TIOCGPTN: - case TIOCSPTLCK: - case TIOCGSERIAL: - case TIOCSSERIAL: - case TIOCSERGETLSR: - - /* Big F */ - case FBIOGTYPE: - case FBIOSATTR: - case FBIOGATTR: - case FBIOSVIDEO: - case FBIOGVIDEO: - case FBIOGCURSOR32: /* This is not implemented yet. Later it should be converted... */ - case FBIOSCURPOS: - case FBIOGCURPOS: - case FBIOGCURMAX: - - case FBIOGET_VSCREENINFO: - case FBIOPUT_VSCREENINFO: - case FBIOPAN_DISPLAY: - case FBIOGET_FCURSORINFO: - case FBIOGET_VCURSORINFO: - case FBIOPUT_VCURSORINFO: - case FBIOGET_CURSORSTATE: - case FBIOPUT_CURSORSTATE: - case FBIOGET_CON2FBMAP: - case FBIOPUT_CON2FBMAP: - - /* Little f */ - case FIOCLEX: - case FIONCLEX: - case FIOASYNC: - case FIONBIO: - case FIONREAD: /* This is also TIOCINQ */ - - /* 0x00 */ - case FIBMAP: - case FIGETBSZ: - - /* 0x03 -- HD/IDE ioctl's used by hdparm and friends. - * Some need translations, these do not. - */ - case HDIO_GET_IDENTITY: - case HDIO_SET_DMA: - case HDIO_SET_KEEPSETTINGS: - case HDIO_SET_UNMASKINTR: - case HDIO_SET_NOWERR: - case HDIO_SET_32BIT: - case HDIO_SET_MULTCOUNT: - case HDIO_DRIVE_CMD: - case HDIO_SET_PIO_MODE: - case HDIO_SCAN_HWIF: - case HDIO_SET_NICE: - case BLKROSET: - case BLKROGET: - - /* 0x02 -- Floppy ioctls */ - case FDMSGON: - case FDMSGOFF: - case FDSETEMSGTRESH: - case FDFLUSH: - case FDWERRORCLR: - case FDSETMAXERRS: - case FDGETMAXERRS: - case FDGETDRVTYP: - case FDEJECT: - case FDCLRPRM: - case FDFMTBEG: - case FDFMTEND: - case FDRESET: - case FDTWADDLE: - case FDFMTTRK: - case FDRAWCMD: - - /* 0x12 */ - case BLKRRPART: - case BLKFLSBUF: - case BLKRASET: +asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int error = -EBADF; + int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp); + struct ioctl_trans *t; -#if 0 /* New RAID code is being merged, fix up to handle - * new RAID ioctls when fully merged in 2.3.x -DaveM - */ - /* 0x09 */ - case REGISTER_DEV: - case REGISTER_DEV_NEW: - case START_MD: - case STOP_MD: -#endif - - /* Big K */ - case PIO_FONT: - case GIO_FONT: - case KDSIGACCEPT: - case KDGETKEYCODE: - case KDSETKEYCODE: - case KIOCSOUND: - case KDMKTONE: - case KDGKBTYPE: - case KDSETMODE: - case KDGETMODE: - case KDSKBMODE: - case KDGKBMODE: - case KDSKBMETA: - case KDGKBMETA: - case KDGKBENT: - case KDSKBENT: - case KDGKBSENT: - case KDSKBSENT: - case KDGKBDIACR: - case KDSKBDIACR: - case KDGKBLED: - case KDSKBLED: - case KDGETLED: - case KDSETLED: - case GIO_SCRNMAP: - case PIO_SCRNMAP: - case GIO_UNISCRNMAP: - case PIO_UNISCRNMAP: - case PIO_FONTRESET: - case PIO_UNIMAPCLR: - - /* Little k */ - case KIOCTYPE: - case KIOCLAYOUT: - case KIOCGTRANS: - case KIOCTRANS: - case KIOCCMD: - case KIOCSDIRECT: - case KIOCSLED: - case KIOCGLED: - case KIOCSRATE: - case KIOCGRATE: - - /* Big S */ - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_DOORLOCK: - case SCSI_IOCTL_DOORUNLOCK: - case SCSI_IOCTL_TEST_UNIT_READY: - case SCSI_IOCTL_TAGGED_ENABLE: - case SCSI_IOCTL_TAGGED_DISABLE: - case SCSI_IOCTL_GET_BUS_NUMBER: - case SCSI_IOCTL_SEND_COMMAND: - - /* Big V */ - case VT_SETMODE: - case VT_GETMODE: - case VT_GETSTATE: - case VT_OPENQRY: - case VT_ACTIVATE: - case VT_WAITACTIVE: - case VT_RELDISP: - case VT_DISALLOCATE: - case VT_RESIZE: - case VT_RESIZEX: - case VT_LOCKSWITCH: - case VT_UNLOCKSWITCH: - - /* Little v */ - case VUIDSFORMAT: - case VUIDGFORMAT: - - /* Little v, the video4linux ioctls */ - case VIDIOCGCAP: - case VIDIOCGCHAN: - case VIDIOCSCHAN: - case VIDIOCGPICT: - case VIDIOCSPICT: - case VIDIOCCAPTURE: - case VIDIOCKEY: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCSYNC: - case VIDIOCMCAPTURE: - case VIDIOCGMBUF: - case VIDIOCGUNIT: - case VIDIOCGCAPTURE: - case VIDIOCSCAPTURE: - - /* BTTV specific... */ - case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]): - case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]): - case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int): - case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */ - case _IOR('v' , BASE_VIDIOCPRIVATE+4, int): - case _IOR('v' , BASE_VIDIOCPRIVATE+5, int): - case _IOR('v' , BASE_VIDIOCPRIVATE+6, int): - case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): - - /* Little p (/dev/rtc, /dev/envctrl, etc.) */ - case RTCGET: - case RTCSET: - case I2CIOCSADR: - case I2CIOCGADR: - - /* Little m */ - case MTIOCTOP: - - /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have - * embedded pointers in the arg which we'd need to clean up... - */ - case OPROMGETOPT: - case OPROMSETOPT: - case OPROMNXTOPT: - case OPROMSETOPT2: - case OPROMNEXT: - case OPROMCHILD: - case OPROMGETPROP: - case OPROMNXTPROP: - case OPROMU2P: - case OPROMGETCONS: - case OPROMGETFBNAME: - case OPROMGETBOOTARGS: - case OPROMSETCUR: - case OPROMPCI2NODE: - case OPROMPATH2NODE: - - /* Socket level stuff */ - case FIOSETOWN: - case SIOCSPGRP: - case FIOGETOWN: - case SIOCGPGRP: - case SIOCATMARK: - case SIOCSIFLINK: - case SIOCSIFENCAP: - case SIOCGIFENCAP: - case SIOCSIFBR: - case SIOCGIFBR: - case SIOCSARP: - case SIOCGARP: - case SIOCDARP: -#if 0 /* XXX No longer exist in new routing code. XXX */ - case OLD_SIOCSARP: - case OLD_SIOCGARP: - case OLD_SIOCDARP: -#endif - case SIOCSRARP: - case SIOCGRARP: - case SIOCDRARP: - case SIOCADDDLCI: - case SIOCDELDLCI: - - /* SG stuff */ - case SG_SET_TIMEOUT: - case SG_GET_TIMEOUT: - case SG_EMULATED_HOST: - case SG_SET_TRANSFORM: - case SG_GET_TRANSFORM: - - /* PPP stuff */ - case PPPIOCGFLAGS: - case PPPIOCSFLAGS: - case PPPIOCGASYNCMAP: - case PPPIOCSASYNCMAP: - case PPPIOCGUNIT: - case PPPIOCGRASYNCMAP: - case PPPIOCSRASYNCMAP: - case PPPIOCGMRU: - case PPPIOCSMRU: - case PPPIOCSMAXCID: - case PPPIOCGXASYNCMAP: - case PPPIOCSXASYNCMAP: - case PPPIOCXFERUNIT: - case PPPIOCGNPMODE: - case PPPIOCSNPMODE: - case PPPIOCGDEBUG: - case PPPIOCSDEBUG: - case PPPIOCNEWUNIT: - case PPPIOCATTACH: - case PPPIOCDETACH: - - /* CDROM stuff */ - case CDROMPAUSE: - case CDROMRESUME: - case CDROMPLAYMSF: - case CDROMPLAYTRKIND: - case CDROMREADTOCHDR: - case CDROMREADTOCENTRY: - case CDROMSTOP: - case CDROMSTART: - case CDROMEJECT: - case CDROMVOLCTRL: - case CDROMSUBCHNL: - case CDROMEJECT_SW: - case CDROMMULTISESSION: - case CDROM_GET_MCN: - case CDROMRESET: - case CDROMVOLREAD: - case CDROMSEEK: - case CDROMPLAYBLK: - case CDROMCLOSETRAY: - case CDROM_SET_OPTIONS: - case CDROM_CLEAR_OPTIONS: - case CDROM_SELECT_SPEED: - case CDROM_SELECT_DISC: - case CDROM_MEDIA_CHANGED: - case CDROM_DRIVE_STATUS: - case CDROM_DISC_STATUS: - case CDROM_CHANGER_NSLOTS: - case CDROM_LOCKDOOR: - case CDROM_DEBUG: - case CDROM_GET_CAPABILITY: - - /* Big L */ - case LOOP_SET_FD: - case LOOP_CLR_FD: - - /* Big A */ - case AUDIO_GETINFO: - case AUDIO_SETINFO: - case AUDIO_DRAIN: - case AUDIO_GETDEV: - case AUDIO_GETDEV_SUNOS: - case AUDIO_FLUSH: - - /* Big Q for sound/OSS */ - case SNDCTL_SEQ_RESET: - case SNDCTL_SEQ_SYNC: - case SNDCTL_SYNTH_INFO: - case SNDCTL_SEQ_CTRLRATE: - case SNDCTL_SEQ_GETOUTCOUNT: - case SNDCTL_SEQ_GETINCOUNT: - case SNDCTL_SEQ_PERCMODE: - case SNDCTL_FM_LOAD_INSTR: - case SNDCTL_SEQ_TESTMIDI: - case SNDCTL_SEQ_RESETSAMPLES: - case SNDCTL_SEQ_NRSYNTHS: - case SNDCTL_SEQ_NRMIDIS: - case SNDCTL_MIDI_INFO: - case SNDCTL_SEQ_THRESHOLD: - case SNDCTL_SYNTH_MEMAVL: - case SNDCTL_FM_4OP_ENABLE: - case SNDCTL_SEQ_PANIC: - case SNDCTL_SEQ_OUTOFBAND: - case SNDCTL_SEQ_GETTIME: - case SNDCTL_SYNTH_ID: - case SNDCTL_SYNTH_CONTROL: - case SNDCTL_SYNTH_REMOVESAMPLE: - - /* Big T for sound/OSS */ - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_SOURCE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SELECT: - - /* Little m for sound/OSS */ - case SNDCTL_MIDI_PRETIME: - case SNDCTL_MIDI_MPUMODE: - case SNDCTL_MIDI_MPUCMD: - - /* Big P for sound/OSS */ - case SNDCTL_DSP_RESET: - case SNDCTL_DSP_SYNC: - case SNDCTL_DSP_SPEED: - case SNDCTL_DSP_STEREO: - case SNDCTL_DSP_GETBLKSIZE: - case SNDCTL_DSP_CHANNELS: - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_POST: - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - case SNDCTL_DSP_GETFMTS: - case SNDCTL_DSP_SETFMT: - case SNDCTL_DSP_GETOSPACE: - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_NONBLOCK: - case SNDCTL_DSP_GETCAPS: - case SNDCTL_DSP_GETTRIGGER: - case SNDCTL_DSP_SETTRIGGER: - case SNDCTL_DSP_GETIPTR: - case SNDCTL_DSP_GETOPTR: - /* case SNDCTL_DSP_MAPINBUF: XXX needs translation */ - /* case SNDCTL_DSP_MAPOUTBUF: XXX needs translation */ - case SNDCTL_DSP_SETSYNCRO: - case SNDCTL_DSP_SETDUPLEX: - case SNDCTL_DSP_GETODELAY: - case SNDCTL_DSP_PROFILE: - - case SOUND_PCM_READ_RATE: - case SOUND_PCM_READ_CHANNELS: - case SOUND_PCM_READ_BITS: - case SOUND_PCM_READ_FILTER: - - /* Big C for sound/OSS */ - case SNDCTL_COPR_RESET: - case SNDCTL_COPR_LOAD: - case SNDCTL_COPR_RDATA: - case SNDCTL_COPR_RCODE: - case SNDCTL_COPR_WDATA: - case SNDCTL_COPR_WCODE: - case SNDCTL_COPR_RUN: - case SNDCTL_COPR_HALT: - case SNDCTL_COPR_SENDMSG: - case SNDCTL_COPR_RCVMSG: - - /* Big M for sound/OSS */ - case SOUND_MIXER_READ_VOLUME: - case SOUND_MIXER_READ_BASS: - case SOUND_MIXER_READ_TREBLE: - case SOUND_MIXER_READ_SYNTH: - case SOUND_MIXER_READ_PCM: - case SOUND_MIXER_READ_SPEAKER: - case SOUND_MIXER_READ_LINE: - case SOUND_MIXER_READ_MIC: - case SOUND_MIXER_READ_CD: - case SOUND_MIXER_READ_IMIX: - case SOUND_MIXER_READ_ALTPCM: - case SOUND_MIXER_READ_RECLEV: - case SOUND_MIXER_READ_IGAIN: - case SOUND_MIXER_READ_OGAIN: - case SOUND_MIXER_READ_LINE1: - case SOUND_MIXER_READ_LINE2: - case SOUND_MIXER_READ_LINE3: - case SOUND_MIXER_READ_MUTE: - /* case SOUND_MIXER_READ_ENHANCE: same value as READ_MUTE */ - /* case SOUND_MIXER_READ_LOUD: same value as READ_MUTE */ - case SOUND_MIXER_READ_RECSRC: - case SOUND_MIXER_READ_DEVMASK: - case SOUND_MIXER_READ_RECMASK: - case SOUND_MIXER_READ_STEREODEVS: - case SOUND_MIXER_READ_CAPS: - - case SOUND_MIXER_WRITE_VOLUME: - case SOUND_MIXER_WRITE_BASS: - case SOUND_MIXER_WRITE_TREBLE: - case SOUND_MIXER_WRITE_SYNTH: - case SOUND_MIXER_WRITE_PCM: - case SOUND_MIXER_WRITE_SPEAKER: - case SOUND_MIXER_WRITE_LINE: - case SOUND_MIXER_WRITE_MIC: - case SOUND_MIXER_WRITE_CD: - case SOUND_MIXER_WRITE_IMIX: - case SOUND_MIXER_WRITE_ALTPCM: - case SOUND_MIXER_WRITE_RECLEV: - case SOUND_MIXER_WRITE_IGAIN: - case SOUND_MIXER_WRITE_OGAIN: - case SOUND_MIXER_WRITE_LINE1: - case SOUND_MIXER_WRITE_LINE2: - case SOUND_MIXER_WRITE_LINE3: - case SOUND_MIXER_WRITE_MUTE: - /* case SOUND_MIXER_WRITE_ENHANCE: same value as WRITE_MUTE */ - /* case SOUND_MIXER_WRITE_LOUD: same value as WRITE_MUTE */ - case SOUND_MIXER_WRITE_RECSRC: - - case SOUND_MIXER_INFO: - case SOUND_OLD_MIXER_INFO: - case SOUND_MIXER_ACCESS: - case SOUND_MIXER_PRIVATE1: - case SOUND_MIXER_PRIVATE2: - case SOUND_MIXER_PRIVATE3: - case SOUND_MIXER_PRIVATE4: - case SOUND_MIXER_PRIVATE5: - case SOUND_MIXER_GETLEVELS: - case SOUND_MIXER_SETLEVELS: - - case OSS_GETVERSION: - - /* AUTOFS */ - case AUTOFS_IOC_READY: - case AUTOFS_IOC_FAIL: - case AUTOFS_IOC_CATATONIC: - case AUTOFS_IOC_PROTOVER: - case AUTOFS_IOC_EXPIRE: - - /* Raw devices */ - case RAW_SETBIND: - case RAW_GETBIND: - - /* SMB ioctls which do not need any translations */ - case SMB_IOC_NEWCONN: - - /* Little a */ - case ATMSIGD_CTRL: - case ATMARPD_CTRL: - case ATMLEC_CTRL: - case ATMLEC_MCAST: - case ATMLEC_DATA: - case ATM_SETSC: - case SIOCSIFATMTCP: - case SIOCMKCLIP: - case ATMARP_MKIP: - case ATMARP_SETENTRY: - case ATMARP_ENCAP: - case ATMTCP_CREATE: - case ATMTCP_REMOVE: - case ATMMPC_CTRL: - case ATMMPC_DATA: - + lock_kernel(); + filp = fget(fd); + if(!filp) + goto out2; + + if (!filp->f_op || !filp->f_op->ioctl) { error = sys_ioctl (fd, cmd, arg); goto out; + } - default: - do { - static int count = 0; - if (++count <= 20) - printk("sys32_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); + t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)]; + + while (t && t->cmd != cmd) + t = (struct ioctl_trans *)(long)t->next; + if (t) { + handler = (void *)(long)t->handler; + error = handler(fd, cmd, arg, filp); + } else { + static int count = 0; + if (++count <= 20) + printk("sys32_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); error = -EINVAL; - break; } out: fput(filp); diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index a09303971..cb659b655 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.82 2000/02/09 11:15:07 davem Exp $ +/* $Id: irq.c,v 1.83 2000/02/11 06:57:17 jj Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -57,7 +57,7 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64))); #ifndef __SMP__ unsigned int __up_workvec[16] __attribute__ ((aligned (64))); -#define irq_work(__cpu, __pil) &(__up_workvec[(__pil)]) +#define irq_work(__cpu, __pil) &(__up_workvec[(void)(__cpu), (__pil)]) #else #define irq_work(__cpu, __pil) &(cpu_data[(__cpu)].irq_worklists[(__pil)]) #endif diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 409a44897..00f635ab3 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -1,4 +1,4 @@ -/* $Id: pci_iommu.c,v 1.8 2000/01/28 13:41:59 jj Exp $ +/* $Id: pci_iommu.c,v 1.10 2000/02/18 13:48:54 davem Exp $ * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -99,13 +99,12 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long return NULL; } -#define IOPTE_CONSISTANT(CTX, PADDR) \ - (IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \ - (((CTX) << 47) & IOPTE_CONTEXT) | \ - ((PADDR) & IOPTE_PAGE)) +#define IOPTE_CONSISTENT(CTX) \ + (IOPTE_VALID | IOPTE_CACHE | \ + (((CTX) << 47) & IOPTE_CONTEXT)) -#define IOPTE_STREAMING(CTX, PADDR) \ - (IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF) +#define IOPTE_STREAMING(CTX) \ + (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) #define IOPTE_INVALID 0UL @@ -123,18 +122,10 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad int npages; size = PAGE_ALIGN(size); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } - if (order == 10) + order = get_order(size); + if (order >= 10) return NULL; - /* We still don't support devices which don't recognize at least 30 bits - of bus address. Bug me to code it (is pretty easy actually). -jj */ - if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff) - BUG(); - first_page = __get_free_pages(GFP_ATOMIC, order); if (first_page == 0UL) return NULL; @@ -160,7 +151,9 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad ctx = iommu->iommu_cur_ctx++; first_page = __pa(first_page); while (npages--) { - iopte_val(*iopte) = IOPTE_CONSISTANT(ctx, first_page); + iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | + IOPTE_WRITE | + (first_page & IOPTE_PAGE)); iopte++; first_page += PAGE_SIZE; } @@ -210,10 +203,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ spin_unlock_irqrestore(&iommu->lock, flags); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } + order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); } @@ -221,7 +211,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ /* Map a single buffer at PTR of SZ bytes for PCI DMA * in streaming mode. */ -dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) +dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -230,14 +220,13 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) unsigned long flags, npages, oaddr; unsigned long i, base_paddr, ctx; u32 bus_addr, ret; + unsigned long iopte_protection; pcp = pdev->sysdata; iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; - /* We still don't support devices which don't recognize at least 30 bits - of bus address. Bug me to code it (is pretty easy actually). -jj */ - if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff) + if (direction == PCI_DMA_NONE) BUG(); oaddr = (unsigned long)ptr; @@ -254,13 +243,15 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) ctx = 0; if (iommu->iommu_ctxflush) ctx = iommu->iommu_cur_ctx++; - if (strbuf->strbuf_enabled) { - for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) - iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); - } else { - for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) - iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr); - } + if (strbuf->strbuf_enabled) + iopte_protection = IOPTE_STREAMING(ctx); + else + iopte_protection = IOPTE_CONSISTENT(ctx); + if (direction != PCI_DMA_TODEVICE) + iopte_protection |= IOPTE_WRITE; + + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = iopte_protection | base_paddr; /* Flush the IOMMU TLB. */ if (iommu->iommu_ctxflush) { @@ -276,7 +267,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) } /* Unmap a single streaming mode DMA translation. */ -void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) +void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -284,6 +275,9 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) iopte_t *base; unsigned long flags, npages, i, ctx; + if (direction == PCI_DMA_NONE) + BUG(); + pcp = pdev->sysdata; iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; @@ -341,7 +335,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) spin_unlock_irqrestore(&iommu->lock, flags); } -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long ctx, int streaming) +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_protection) { struct scatterlist *dma_sg = sg; int i; @@ -381,10 +375,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, un sg++; } - if (streaming) - pteval = IOPTE_STREAMING(ctx, pteval); - else - pteval = IOPTE_CONSISTANT(ctx, pteval); + pteval = iopte_protection | (pteval & IOPTE_PAGE); while (len > 0) { *iopte++ = __iopte(pteval); pteval += PAGE_SIZE; @@ -419,12 +410,12 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, un * When making changes here, inspect the assembly output. I was having * hard time to kepp this routine out of using stack slots for holding variables. */ -int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; - unsigned long flags, ctx, i, npages; + unsigned long flags, ctx, i, npages, iopte_protection; iopte_t *base; u32 dma_base; struct scatterlist *sgtmp; @@ -432,7 +423,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) /* Fast path single entry scatterlists. */ if (nelems == 1) { - sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length); + sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length, direction); sglist->dvma_length = sglist->length; return 1; } @@ -441,9 +432,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; - /* We still don't support devices which don't recognize at least 30 bits - of bus address. Bug me to code it (is pretty easy actually). -jj */ - if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff) + if (direction == PCI_DMA_NONE) BUG(); /* Step 1: Prepare scatter list. */ @@ -474,7 +463,13 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) ctx = iommu->iommu_cur_ctx++; /* Step 5: Create the mappings. */ - fill_sg (base, sglist, used, ctx, strbuf->strbuf_enabled); + if (strbuf->strbuf_enabled) + iopte_protection = IOPTE_STREAMING(ctx); + else + iopte_protection = IOPTE_CONSISTENT(ctx); + if (direction != PCI_DMA_TODEVICE) + iopte_protection |= IOPTE_WRITE; + fill_sg (base, sglist, used, iopte_protection); #ifdef VERIFY_SG verify_sglist(sglist, nelems, base, npages); #endif @@ -493,7 +488,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) } /* Unmap a set of streaming mode DMA translations. */ -void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -502,6 +497,9 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) unsigned long flags, ctx, i, npages; u32 bus_addr; + if (direction == PCI_DMA_NONE) + BUG(); + pcp = pdev->sysdata; iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; @@ -568,7 +566,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) /* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. */ -void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) +void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -629,7 +627,7 @@ void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. */ -void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -690,3 +688,19 @@ void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelem spin_unlock_irqrestore(&iommu->lock, flags); } + +int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + u32 dma_addr_mask; + + if (pdev == NULL) { + dma_addr_mask = 0xffffffff; + } else { + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + + dma_addr_mask = iommu->dma_addr_mask; + } + + return (device_mask & dma_addr_mask) == dma_addr_mask; +} diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index c9bd41c19..b3248de39 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.11 2000/02/08 05:11:32 jj Exp $ +/* $Id: pci_psycho.c,v 1.13 2000/02/18 13:48:54 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1264,6 +1264,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) p->iommu.page_table = (iopte_t *)tsbbase; p->iommu.page_table_sz_bits = 17; p->iommu.page_table_map_base = 0xc0000000; + p->iommu.dma_addr_mask = 0xffffffff; memset((char *)tsbbase, 0, PAGE_SIZE << 7); /* Make sure DMA address 0 is never returned just to allow catching @@ -1344,9 +1345,7 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p, int is_pbm_a) { unsigned long base = p->controller_regs; - - /* Currently we don't even use it. */ - pbm->stc.strbuf_enabled = 0; + u64 control; if (is_pbm_a) { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; @@ -1368,14 +1367,29 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p, pbm->stc.strbuf_flushflag_pa = (unsigned long) __pa(pbm->stc.strbuf_flushflag); -#if 0 - /* And when we do enable it, these are the sorts of things - * we'll do. + /* Enable the streaming buffer. We have to be careful + * just in case OBP left it with LRU locking enabled. + * + * It is possible to control if PBM will be rerun on + * line misses. Currently I just retain whatever setting + * OBP left us with. All checks so far show it having + * a value of zero. */ +#undef PSYCHO_STRBUF_RERUN_ENABLE +#undef PSYCHO_STRBUF_RERUN_DISABLE control = psycho_read(pbm->stc.strbuf_control); - control |= PSYCHO_SBUFCTRL_SB_EN; - psycho_write(pbm->stc.strbuf_control, control); + control |= PSYCHO_STRBUF_CTRL_ENAB; + control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR); +#ifdef PSYCHO_STRBUF_RERUN_ENABLE + control &= ~(PSYCHO_STRBUF_CTRL_RRDIS); +#else +#ifdef PSYCHO_STRBUF_RERUN_DISABLE + control |= PSYCHO_STRBUF_CTRL_RRDIS; #endif +#endif + psycho_write(pbm->stc.strbuf_control, control); + + pbm->stc.strbuf_enabled = 1; } #define PSYCHO_IOSPACE_A 0x002000000UL diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index bbf10cac1..e96af490d 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.12 2000/02/08 05:11:33 jj Exp $ +/* $Id: pci_sabre.c,v 1.14 2000/02/18 13:48:55 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1105,7 +1105,8 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) } static void __init sabre_iommu_init(struct pci_controller_info *p, - int tsbsize, unsigned long dvma_offset) + int tsbsize, unsigned long dvma_offset, + u32 dma_mask) { unsigned long tsbbase, i, order; u64 control; @@ -1133,16 +1134,14 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, control &= ~(SABRE_IOMMUCTRL_DENAB); sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); - for(order = 0;; order++) - if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) - break; - tsbbase = __get_free_pages(GFP_KERNEL, order); + tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); } p->iommu.page_table = (iopte_t *)tsbbase; p->iommu.page_table_map_base = dvma_offset; + p->iommu.dma_addr_mask = dma_mask; memset((char *)tsbbase, 0, PAGE_SIZE << order); /* Make sure DMA address 0 is never returned just to allow catching @@ -1315,7 +1314,7 @@ void __init sabre_init(int pnode) int tsbsize, err; u32 busrange[2]; u32 vdma[2]; - u32 upa_portid; + u32 upa_portid, dma_mask; int bus; p = kmalloc(sizeof(*p), GFP_ATOMIC); @@ -1375,12 +1374,19 @@ void __init sabre_init(int pnode) prom_halt(); } + dma_mask = vdma[0]; switch(vdma[1]) { case 0x20000000: + dma_mask |= 0x1fffffff; tsbsize = 64; break; case 0x40000000: + dma_mask |= 0x3fffffff; + tsbsize = 128; + break; + case 0x80000000: + dma_mask |= 0x7fffffff; tsbsize = 128; break; default: @@ -1388,7 +1394,7 @@ void __init sabre_init(int pnode) prom_halt(); } - sabre_iommu_init(p, tsbsize, vdma[0]); + sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 38e731f37..1b454fa2c 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.7 2000/01/28 13:41:58 jj Exp $ +/* $Id: sbus.c,v 1.9 2000/02/18 13:48:57 davem Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -255,11 +255,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma return NULL; size = PAGE_ALIGN(size); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } - if (order == 10) + order = get_order(size); + if (order >= 10) return NULL; first_page = __get_free_pages(GFP_KERNEL, order); if (first_page == 0UL) @@ -306,20 +303,21 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add free_consistent_cluster(iommu, dvma, npages); spin_unlock_irq(&iommu->lock); - for (order = 0; order < 10; order++) { - if ((PAGE_SIZE << order) >= size) - break; - } + order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); } -dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size) +dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long npages, phys_base, flags; iopte_t *iopte; u32 dma_base, offset; + unsigned long iopte_bits; + + if (dir == SBUS_DMA_NONE) + BUG(); phys_base = (unsigned long) ptr; offset = (u32) (phys_base & ~PAGE_MASK); @@ -331,10 +329,11 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size) iopte = alloc_streaming_cluster(iommu, npages); dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); npages = size >> PAGE_SHIFT; + iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; + if (dir != SBUS_DMA_TODEVICE) + iopte_bits |= IOPTE_WRITE; while (npages--) { - *iopte++ = __iopte(IOPTE_VALID | IOPTE_STBUF | - IOPTE_CACHE | IOPTE_WRITE | - (phys_base & IOPTE_PAGE)); + *iopte++ = __iopte(iopte_bits | (phys_base & IOPTE_PAGE)); phys_base += PAGE_SIZE; } npages = size >> PAGE_SHIFT; @@ -344,7 +343,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size) return (dma_base | offset); } -void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size) +void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; u32 dma_base = dma_addr & PAGE_MASK; @@ -358,7 +357,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size) spin_unlock_irqrestore(&iommu->lock, flags); } -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused) +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_bits) { struct scatterlist *dma_sg = sg; int i; @@ -398,9 +397,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused) sg++; } - pteval = ((pteval & IOPTE_PAGE) | - IOPTE_VALID | IOPTE_STBUF | - IOPTE_CACHE | IOPTE_WRITE); + pteval = ((pteval & IOPTE_PAGE) | iopte_bits); while (len > 0) { *iopte++ = __iopte(pteval); pteval += PAGE_SIZE; @@ -430,7 +427,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused) } } -int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int dir) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, npages; @@ -438,10 +435,14 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) u32 dma_base; struct scatterlist *sgtmp; int used; + unsigned long iopte_bits; + + if (dir == SBUS_DMA_NONE) + BUG(); /* Fast path single entry scatterlists. */ if (nents == 1) { - sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length); + sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length, dir); sg->dvma_length = sg->length; return 1; } @@ -463,7 +464,11 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) } used = nents - used; - fill_sg(iopte, sg, used); + iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; + if (dir != SBUS_DMA_TODEVICE) + iopte_bits |= IOPTE_WRITE; + + fill_sg(iopte, sg, used, iopte_bits); #ifdef VERIFY_SG verify_sglist(sg, nents, iopte, npages); #endif @@ -473,7 +478,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) return used; } -void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) { unsigned long size, flags; struct sbus_iommu *iommu; @@ -482,7 +487,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) /* Fast path single entry scatterlists. */ if (nents == 1) { - sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length); + sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length, direction); return; } @@ -501,7 +506,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) spin_unlock_irqrestore(&iommu->lock, flags); } -void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size) +void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags; @@ -513,7 +518,7 @@ void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size) spin_unlock_irqrestore(&iommu->lock, flags); } -void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, size; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 6e8899435..273c12de1 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -753,9 +753,7 @@ static void __init smp_tune_scheduling (void) "ecache-size", (512 * 1024)); if (ecache_size > (4 * 1024 * 1024)) ecache_size = (4 * 1024 * 1024); - for (order = 0UL; (PAGE_SIZE << order) < ecache_size; order++) - ; - flush_base = __get_free_pages(GFP_KERNEL, order); + flush_base = __get_free_pages(GFP_KERNEL, order = get_order(ecache_size)); if (flush_base != 0UL) { __save_and_cli(flags); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index be2638ec9..81b4c4de1 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.35 2000/01/29 07:40:12 davem Exp $ +/* $Id: sys_sparc.c,v 1.36 2000/02/16 07:31:35 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -39,17 +39,49 @@ asmlinkage unsigned long sys_getpagesize(void) return PAGE_SIZE; } +unsigned long get_unmapped_area(unsigned long addr, unsigned long len) +{ + struct vm_area_struct * vmm; + unsigned long task_size = TASK_SIZE; + + if (current->thread.flags & SPARC_FLAG_32BIT) + task_size = 0xf0000000UL; + if (len > task_size || len > -PAGE_OFFSET) + return 0; + if (!addr) + addr = TASK_UNMAPPED_BASE; + addr = PAGE_ALIGN(addr); + + task_size -= len; + + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) { + addr = PAGE_OFFSET; + vmm = find_vma(current->mm, PAGE_OFFSET); + } + if (task_size < addr) + return 0; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + } +} + extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { - if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) || - (brk - current->mm->brk > 0x80000000000UL && - brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */ + /* People could try to be nasty and use ta 0x6d in 32bit programs */ + if ((current->thread.flags & SPARC_FLAG_32BIT) && + brk >= 0xf0000000UL) + return current->mm->brk; + + if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET)) return current->mm->brk; return sys_brk(brk); } - + /* * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. @@ -164,30 +196,21 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - retval = -ENOMEM; len = PAGE_ALIGN(len); + retval = -EINVAL; + down(¤t->mm->mmap_sem); lock_kernel(); - if(!(flags & MAP_FIXED) && !addr) { - addr = get_unmapped_area(addr, len); - if(!addr) - goto out_putf; - } - retval = -EINVAL; if (current->thread.flags & SPARC_FLAG_32BIT) { - if (len > 0xf0000000UL || addr > 0xf0000000UL - len) + if (len > 0xf0000000UL || + ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) goto out_putf; } else { - if (len >= 0x80000000000UL || - (addr < 0x80000000000UL && - addr > 0x80000000000UL-len)) + if (len > -PAGE_OFFSET || + ((flags & MAP_FIXED) && + addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) goto out_putf; - if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) { - /* VM hole */ - retval = current->mm->brk; - goto out_putf; - } } retval = do_mmap(file, addr, len, prot, flags, off); @@ -201,6 +224,55 @@ out: return retval; } +asmlinkage long sys64_munmap(unsigned long addr, size_t len) +{ + long ret; + + if (len > -PAGE_OFFSET || + (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) + return -EINVAL; + down(¤t->mm->mmap_sem); + ret = do_munmap(addr, len); + up(¤t->mm->mmap_sem); + return ret; +} + +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sys64_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr) +{ + unsigned long ret = -EINVAL; + if (current->thread.flags & SPARC_FLAG_32BIT) + goto out; + if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET) + goto out; + if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (new_addr < PAGE_OFFSET && + new_addr + new_len > -PAGE_OFFSET) + goto out_sem; + } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} + /* we come to here via sys_nis_syscall so it can setup the regs argument */ asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 61b9a3397..1ebb7772c 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.131 2000/01/21 11:38:54 jj Exp $ +/* $Id: sys_sparc32.c,v 1.132 2000/02/16 07:31:35 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -44,6 +44,7 @@ #include <linux/filter.h> #include <linux/highmem.h> #include <linux/highuid.h> +#include <linux/mman.h> #include <asm/types.h> #include <asm/ipc.h> @@ -4190,3 +4191,38 @@ out_error: fd = error; goto out; } + +extern unsigned long do_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, unsigned long new_addr); + +asmlinkage unsigned long sys32_mremap(unsigned long addr, + unsigned long old_len, unsigned long new_len, + unsigned long flags, u32 __new_addr) +{ + unsigned long ret = -EINVAL; + unsigned long new_addr = AA(__new_addr); + + if (old_len > 0xf0000000UL || new_len > 0xf0000000UL) + goto out; + if (addr > 0xf0000000UL - old_len) + goto out; + down(¤t->mm->mmap_sem); + if (flags & MREMAP_FIXED) { + if (new_addr > 0xf0000000UL - new_len) + goto out_sem; + } else if (addr > 0xf0000000UL - new_len) { + ret = -ENOMEM; + if (!(flags & MREMAP_MAYMOVE)) + goto out_sem; + new_addr = get_unmapped_area (addr, new_len); + if (!new_addr) + goto out_sem; + flags |= MREMAP_FIXED; + } + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +out_sem: + up(¤t->mm->mmap_sem); +out: + return ret; +} diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 62058ffcf..c5101248a 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.38 2000/01/29 07:40:13 davem Exp $ +/* $Id: sys_sunos32.c,v 1.39 2000/02/16 07:31:37 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -71,8 +71,10 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { - printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", - current->comm); + static int cnt; + if (cnt++ < 10) + printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", + current->comm); flags &= ~MAP_NORESERVE; } retval = -EBADF; @@ -93,15 +95,11 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of } } - retval = -ENOMEM; - if(!(flags & MAP_FIXED) && !addr) { - unsigned long attempt = get_unmapped_area(addr, len); - if(!attempt || (attempt >= 0xf0000000UL)) - goto out_putf; - addr = (u32) attempt; - } + retval = -EINVAL; if(!(flags & MAP_FIXED)) addr = 0; + else if (len > 0xf0000000 || addr > 0xf0000000 - len) + goto out_putf; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 10effccae..1f7ab3fef 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.67 2000/01/29 16:41:21 jj Exp $ +/* $Id: systbls.S,v 1.68 2000/02/16 07:31:38 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -69,7 +69,7 @@ sys_call_table32: .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl +/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl .word sys_aplib /* Now the 64-bit native Linux syscall table. */ @@ -92,7 +92,7 @@ sys_call_table: .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize .word sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall -/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect +/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys64_munmap, sys_mprotect .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups /*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall @@ -128,7 +128,7 @@ sys_call_table: .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_aplib #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index cb281a659..0825b0585 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.36 1999/12/15 15:45:18 davem Exp $ +/* $Id: ultra.S,v 1.37 2000/02/14 02:52:04 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -132,8 +132,8 @@ __flush_tlb_range_pbp_slow: wrpr %g1, 0x0, %pstate .align 32 - .globl flush_icache_page -flush_icache_page: /* %o0 = phys_page */ + .globl __flush_icache_page +__flush_icache_page: /* %o0 = phys_page */ sethi %hi(1 << 13), %o2 ! IC_set bit mov 1, %g1 srlx %o0, 5, %o0 diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 46dbfb241..9e2bd4118 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.21 2000/01/29 07:40:15 davem Exp $ +/* $Id: misc.c,v 1.22 2000/02/16 07:31:41 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -83,27 +83,25 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o } } - down(¤t->mm->mmap_sem); - retval = -ENOMEM; - if(!(flags & MAP_FIXED) && !addr) { - unsigned long attempt = get_unmapped_area(addr, len); - if(!attempt || (attempt >= 0xf0000000UL)) - goto out_putf; - addr = (u32) attempt; - } + retval = -EINVAL; + len = PAGE_ALIGN(len); if(!(flags & MAP_FIXED)) addr = 0; + else if (len > 0xf0000000UL || addr > 0xf0000000UL - len) + goto out_putf; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; + down(¤t->mm->mmap_sem); flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, off); + up(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < 0xf0000000) ? 0 : retval); + out_putf: - up(¤t->mm->mmap_sem); if (file) fput(file); out: diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index b5f76d400..89f771609 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.11 2000/02/09 22:32:17 davem Exp $ +/* $Id: socksys.c,v 1.12 2000/02/17 05:50:11 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/malloc.h> +#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include <asm/termios.h> @@ -157,6 +158,8 @@ static struct file_operations socksys_fops = { release: socksys_release, }; +static devfs_handle_t devfs_handle = NULL; + int __init init_socksys(void) { @@ -167,7 +170,7 @@ init_socksys(void) int (*sys_close)(unsigned int) = (int (*)(unsigned int))SYS(close); - ret = register_chrdev (30, "socksys", &socksys_fops); + ret = devfs_register_chrdev (30, "socksys", &socksys_fops); if (ret < 0) { printk ("Couldn't register socksys character device\n"); return ret; @@ -177,6 +180,10 @@ init_socksys(void) printk ("Couldn't create socket\n"); return ret; } + devfs_handle = devfs_register (NULL, "socksys", 0, DEVFS_FL_NONE, + 30, 0, + S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, + &socksys_fops, NULL); file = fcheck(ret); /* N.B. Is this valid? Suppose the f_ops are in a module ... */ socksys_file_ops = *file->f_op; @@ -190,6 +197,7 @@ init_socksys(void) void cleanup_socksys(void) { - if (unregister_chrdev (30, "socksys")) + if (devfs_unregister_chrdev(30, "socksys")) printk ("Couldn't unregister socksys character device\n"); + devfs_unregister (devfs_handle); } |