From f3453549aab4e82024f0039d6d48adde0e3ea0d8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:35:13 -0500 Subject: [PATCH] Import 2.3.99pre10-3 --- CREDITS | 7 + Documentation/Configure.help | 15 + Documentation/sound/OPL3-SA2 | 2 +- MAINTAINERS | 2 +- arch/alpha/kernel/signal.c | 32 +- arch/arm/kernel/signal.c | 37 +- arch/i386/config.in | 7 + arch/i386/defconfig | 3 + arch/i386/kernel/Makefile | 16 + arch/i386/kernel/apm.c | 42 +- arch/i386/kernel/cpuid.c | 168 ++ arch/i386/kernel/i8259.c | 3 +- arch/i386/kernel/msr.c | 274 +++ arch/i386/kernel/setup.c | 123 +- arch/i386/kernel/signal.c | 37 +- arch/i386/kernel/traps.c | 104 +- arch/i386/mm/fault.c | 22 +- arch/ia64/ia32/ia32_signal.c | 49 +- arch/ia64/kernel/signal.c | 39 +- arch/m68k/kernel/signal.c | 37 +- arch/mips/kernel/signal.c | 37 +- arch/mips64/kernel/signal.c | 37 +- arch/ppc/kernel/signal.c | 35 + arch/sh/kernel/signal.c | 37 +- arch/sparc/kernel/signal.c | 34 +- arch/sparc64/kernel/signal.c | 34 +- arch/sparc64/kernel/signal32.c | 26 +- arch/sparc64/kernel/sys_sparc32.c | 93 +- drivers/block/ll_rw_blk.c | 9 - drivers/block/lvm-snap.c | 4 +- drivers/block/lvm.c | 117 +- drivers/block/md.c | 3 +- drivers/block/rd.c | 2 + drivers/cdrom/aztcd.c | 3 +- drivers/char/bttv.c | 2 +- drivers/char/cpia.c | 2 +- drivers/char/sx.c | 2 +- drivers/i2o/i2o_core.c | 328 +++- drivers/ide/ide-pnp.c | 2 +- drivers/net/dgrs.c | 1 + drivers/pci/pci.ids | 5 +- drivers/usb/ibmcam.c | 2 +- drivers/usb/ov511.c | 2 +- drivers/video/Config.in | 14 +- drivers/video/Makefile | 1 + drivers/video/fbmem.c | 5 + drivers/video/sisfb.c | 2982 +++++++++++++++++++++++++++++ fs/block_dev.c | 4 +- fs/fcntl.c | 12 +- fs/nfsd/nfscache.c | 2 +- fs/partitions/check.c | 12 - include/asm-alpha/siginfo.h | 119 +- include/asm-arm/siginfo.h | 119 +- include/asm-i386/processor.h | 1 + include/asm-i386/siginfo.h | 119 +- include/asm-i386/spinlock.h | 9 +- include/asm-ia64/ia32.h | 55 + include/asm-ia64/siginfo.h | 139 +- include/asm-m68k/siginfo.h | 119 +- include/asm-mips/siginfo.h | 107 +- include/asm-mips64/siginfo.h | 109 +- include/asm-ppc/siginfo.h | 119 +- include/asm-sh/siginfo.h | 119 +- include/asm-sparc/siginfo.h | 121 +- include/asm-sparc64/siginfo.h | 118 +- include/linux/fs.h | 17 +- include/linux/kernel.h | 1 - include/linux/lvm.h | 8 +- include/linux/major.h | 3 + include/linux/sisfb.h | 35 + include/linux/smp.h | 1 + init/main.c | 2 + kernel/acct.c | 5 +- kernel/ksyms.c | 7 - kernel/signal.c | 22 +- 75 files changed, 5552 insertions(+), 790 deletions(-) create mode 100644 arch/i386/kernel/cpuid.c create mode 100644 arch/i386/kernel/msr.c create mode 100644 drivers/video/sisfb.c create mode 100644 include/linux/sisfb.h diff --git a/CREDITS b/CREDITS index b0f58d59646e..a749e65788c3 100644 --- a/CREDITS +++ b/CREDITS @@ -550,6 +550,13 @@ S: 550 King Street S: Littleton, Massachusetts 01460 S: USA +N: Frank Davis +E: fdavis112@juno.com +D: Various kernel patches +S: 8 Lakeview Terr. +S: Kerhonskon, NY 12446 +S: USA + N: Wayne Davison E: davison@borland.com D: Second extended file system co-designer diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 467327737eb4..86a6f345fdf8 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -12647,6 +12647,21 @@ CONFIG_MICROCODE The module will be called microcode.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +/dev/cpu/*/msr - Model-specific register support +CONFIG_X86_MSR + This device gives privileged processes access to the x86 + Model-Specific Registers (MSRs). It is a character device with + major 202 and minors 0 to 31 for /dev/cpu/0/msr to /dev/cpu/31/msr. + MSR accesses are directed to a specific CPU on multi-processor + systems. + +/dev/cpu/*/cpuid - CPU information support +CONFIG_X86_CPUID + This device gives processes access to the x86 CPUID instruction to + be executed on a specific processor. It is a character device + with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to + /dev/cpu/31/cpuid. + Enhanced Real Time Clock Support CONFIG_RTC If you say Y here and create a character special file /dev/rtc with diff --git a/Documentation/sound/OPL3-SA2 b/Documentation/sound/OPL3-SA2 index e6bca70896d4..d43ba0475832 100644 --- a/Documentation/sound/OPL3-SA2 +++ b/Documentation/sound/OPL3-SA2 @@ -1,7 +1,7 @@ Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o) --------------------------------------------------------------- -Scott Murray, scottm@interlog.com +Scott Murray, scott@spiteful.org January 5, 1999 NOTE: All trade-marked terms mentioned below are properties of their diff --git a/MAINTAINERS b/MAINTAINERS index 764f931192ee..069e3b2ed38b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -665,7 +665,7 @@ W: http://www.acc.umu.se/~mcalinux/ L: linux-kernel@vger.rutgers.edu S: Maintained -MODULE SUPPORT [GENERAL], KERNELD +MODULE SUPPORT [GENERAL], KMOD P: Keith Owens M: kaos@ocs.com.au L: linux-kernel@vger.rutgers.edu diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index ff12b9e8d960..1f70c98e6b83 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -36,6 +36,36 @@ asmlinkage int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *, unsigned long, unsigned long); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_addr, &to->si_addr); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * The OSF/1 sigprocmask calling sequence is different from the * C sigprocmask() sequence.. @@ -489,7 +519,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 54d962790de3..15f8fb4cb2e5 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -34,6 +34,41 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); extern int ptrace_cancel_bpt (struct task_struct *); extern int ptrace_set_bpt (struct task_struct *); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * atomically swap in the new signal mask, and wait for a signal. */ @@ -370,7 +405,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); diff --git a/arch/i386/config.in b/arch/i386/config.in index 5bc10fd501f6..830bb2687f96 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -25,6 +25,7 @@ choice 'Processor family' \ PPro/P-II/P-III CONFIG_M686 \ Pentium-III CONFIG_M686FX \ K6/II/III CONFIG_MK6 \ + Crusoe CONFIG_MCRUSOE \ Athlon CONFIG_MK7" PPro # # Define implied options from the CPU selection here @@ -54,6 +55,10 @@ if [ "$CONFIG_M586TSC" = "y" ]; then define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_TSC y fi +if [ "$CONFIG_MCRUSOE" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_TSC y +fi if [ "$CONFIG_M686" = "y" ]; then define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_TSC y @@ -85,6 +90,8 @@ if [ "$CONFIG_MK7" = "y" ]; then fi tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR +tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID choice 'High Memory Support' \ "off CONFIG_NOHIGHMEM \ diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 925311887515..b8623d115524 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -21,6 +21,7 @@ CONFIG_UID16=y CONFIG_M686=y # CONFIG_M686FX is not set # CONFIG_MK6 is not set +# CONFIG_MCRUSOE is not set # CONFIG_MK7 is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y @@ -33,6 +34,8 @@ CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y # CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 56db72ef82fb..9e9b7684805e 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -40,6 +40,22 @@ else endif endif +ifeq ($(CONFIG_X86_MSR),y) +OX_OBJS += msr.o +else + ifeq ($(CONFIG_X86_MSR),m) + MX_OBJS += msr.o + endif +endif + +ifeq ($(CONFIG_X86_CPUID),y) +OX_OBJS += cpuid.o +else + ifeq ($(CONFIG_X86_CPUID),m) + MX_OBJS += cpuid.o + endif +endif + ifeq ($(CONFIG_MICROCODE),y) OX_OBJS += microcode.o else diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index b1e0e8b7c612..0b4517137498 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -922,6 +922,10 @@ static int send_event(apm_event_t event, struct apm_user *sender) case APM_USER_SUSPEND: /* map all suspends to ACPI D3 */ if (pm_send_all(PM_SUSPEND, (void *)3)) { + if (event == APM_CRITICAL_SUSPEND) { + printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armagedon\n" ); + return 0; + } if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; @@ -934,7 +938,6 @@ static int send_event(apm_event_t event, struct apm_user *sender) break; } - queue_event(event, sender); return 1; } @@ -964,6 +967,7 @@ static void check_events(void) case APM_SYS_STANDBY: case APM_USER_STANDBY: if (send_event(event, NULL)) { + queue_event(event, NULL); if (standbys_pending <= 0) standby(); } @@ -980,17 +984,18 @@ static void check_events(void) if (ignore_bounce) break; #endif - /* - * If we are already processing a SUSPEND, - * then further SUSPEND events from the BIOS - * will be ignored. We also return here to - * cope with the fact that the Thinkpads keep - * sending a SUSPEND event until something else - * happens! - */ + /* + * If we are already processing a SUSPEND, + * then further SUSPEND events from the BIOS + * will be ignored. We also return here to + * cope with the fact that the Thinkpads keep + * sending a SUSPEND event until something else + * happens! + */ if (waiting_for_resume) - return; + return; if (send_event(event, NULL)) { + queue_event(event, NULL); waiting_for_resume = 1; if (suspends_pending <= 0) (void) suspend(); @@ -1007,6 +1012,7 @@ static void check_events(void) #endif set_time(); send_event(event, NULL); + queue_event(event, NULL); break; case APM_CAPABILITY_CHANGE: @@ -1020,6 +1026,7 @@ static void check_events(void) break; case APM_CRITICAL_SUSPEND: + send_event(event, NULL); /* We can only hope it worked; critical suspend may not fail */ (void) suspend(); break; } @@ -1056,6 +1063,7 @@ static void apm_event_handler(void) static void apm_mainloop(void) { + int timeout = HZ; DECLARE_WAITQUEUE(wait, current); if (smp_num_cpus > 1) @@ -1065,7 +1073,10 @@ static void apm_mainloop(void) current->state = TASK_INTERRUPTIBLE; for (;;) { /* Nothing to do, just sleep for the timeout */ - schedule_timeout(APM_CHECK_TIMEOUT); + timeout = 2*timeout; + if (timeout > APM_CHECK_TIMEOUT) + timeout = APM_CHECK_TIMEOUT; + schedule_timeout(timeout); if (exit_kapmd) break; @@ -1080,13 +1091,16 @@ static void apm_mainloop(void) continue; if (apm_do_idle()) { unsigned long start = jiffies; - while (system_idle()) { + while ((!exit_kapmd) && system_idle()) { apm_do_idle(); - if (jiffies - start > APM_CHECK_TIMEOUT) - break; + if (jiffies - start > (5*APM_CHECK_TIMEOUT)) { + apm_event_handler(); + start = jiffies; + } } apm_do_busy(); apm_event_handler(); + timeout = 1; } #endif } diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c new file mode 100644 index 000000000000..9395e7094897 --- /dev/null +++ b/arch/i386/kernel/cpuid.c @@ -0,0 +1,168 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2000 H. Peter Anvin - All Rights Reserved + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + + +/* + * cpuid.c + * + * x86 CPUID access device + * + * This device is accessed by lseek() to the appropriate CPUID level + * and then read in chunks of 16 bytes. A larger size means multiple + * reads of consecutive levels. + * + * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on + * an SMP box will direct the access to CPU %d. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_SMP + +struct cpuid_command { + int cpu; + u32 reg; + u32 *data; +}; + +static void cpuid_smp_cpuid(void *cmd_block) +{ + struct cpuid_command *cmd = (struct cpuid_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]); +} + +extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +{ + struct cpuid_command cmd; + + if ( cpu == smp_processor_id() ) { + cpuid(reg, &data[0], &data[1], &data[2], &data[3]); + } else { + cmd->cpu = cpu; + cmd->reg = reg; + cmd->data = data; + + smp_call_function(cpuid_smp_cpuid, (void *)cmd, 1, 1); + } +} +#else /* ! __SMP__ */ + +extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +{ + cpuid(reg, &data[0], &data[1], &data[2], &data[3]); +} + +#endif /* ! __SMP__ */ + +static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; /* SEEK_END not supported */ + } +} + +static ssize_t cpuid_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + u32 *tmp = (u32 *)buf; + u32 data[4]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( count % 16 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 16 ) { + do_cpuid(cpu, reg, data); + if ( copy_to_user(tmp,&data,16) ) + return -EFAULT; + tmp += 4; + *ppos = reg++; + } + + return ((char *)tmp) - buf; +} + +static int cpuid_open(struct inode *inode, struct file *file) +{ + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( !(cpu_online_map & (1UL << cpu)) ) + return -ENXIO; /* No such CPU */ + + MOD_INC_USE_COUNT; + return 0; +} + +static int cpuid_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * File operations we support + */ +static struct file_operations cpuid_fops = { + llseek: cpuid_seek, + read: cpuid_read, + open: cpuid_open, + release: cpuid_release, +}; + +int __init cpuid_init(void) +{ + if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) { + printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n", + CPUID_MAJOR); + return -EBUSY; + } + + return 0; +} + +void __exit cpuid_exit(void) +{ +} + +module_init(cpuid_init); +module_exit(cpuid_exit) + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("H. Peter Anvin "); +MODULE_DESCRIPTION("x86 generic CPUID driver"); diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index e88fa90229b4..fff171c241a5 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -390,10 +390,11 @@ void __init init_8259A(int auto_eoi) static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) { + extern void math_error(void *); outb(0,0xF0); if (ignore_irq13 || !boot_cpu_data.hard_math) return; - math_error(); + math_error((void *)regs->eip); } static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c new file mode 100644 index 000000000000..a83f4deeb3d0 --- /dev/null +++ b/arch/i386/kernel/msr.c @@ -0,0 +1,274 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2000 H. Peter Anvin - All Rights Reserved + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * msr.c + * + * x86 MSR access device + * + * This device is accessed by lseek() to the appropriate register number + * and then read/write in chunks of 8 bytes. A larger size means multiple + * reads or writes of the same register. + * + * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on + * an SMP box will direct the access to CPU %d. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) +{ + int err = 0; + + asm volatile( + "1: wrmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "+r" (err) + : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO)); + + return err; +} + +extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) +{ + int err = 0; + + asm volatile( + "1: rdmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "+r" (err), "=a" (*eax), "=d" (*eax) + : "c" (reg), "i" (-EIO)); + + return err; +} + +#ifdef CONFIG_SMP + +struct msr_command { + int cpu; + int err; + u32 reg; + u32 data[2]; +}; + +static void msr_smp_wrmsr(void *cmd_block) +{ + struct msr_command *cmd = (struct msr_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cmd->err = wrmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); +} + +static void msr_smp_rdmsr(void *cmd_block) +{ + struct msr_command *cmd = (struct msr_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); +} + +extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +{ + struct msr_command cmd; + + if ( cpu == smp_processor_id() ) { + return wrmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + cmd.data[0] = eax; + cmd.data[1] = edx; + + smp_call_function(msr_smp_wrmsr, (void *)cmd, 1, 1); + return cmd.err; + } +} + +extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +{ + struct msr_command cmd; + + if ( cpu == smp_processor_id() ) { + return rdmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + + smp_call_function(msr_smp_rdmsr, (void *)cmd, 1, 1); + + *eax = cmd.data[0]; + *edx = cmd.data[1]; + + return cmd.err; + } +} + +#else /* ! __SMP__ */ + +extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +{ + return wrmsr_eio(reg, eax, edx); +} + +extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +{ + return rdmsr_eio(reg, eax, edx); +} + +#endif /* ! __SMP__ */ + +static loff_t msr_seek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; /* SEEK_END not supported */ + } +} + +static ssize_t msr_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + u32 *tmp = (u32 *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int err; + + if ( count % 8 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 8 ) { + err = do_rdmsr(cpu, reg, &data[0], &data[1]); + if ( err ) + return err; + if ( copy_to_user(tmp,&data,8) ) + return -EFAULT; + tmp += 2; + } + + return ((char *)tmp) - buf; +} + +static ssize_t msr_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + const u32 *tmp = (const u32 *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int err; + + if ( count % 8 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 8 ) { + if ( copy_from_user(&data,tmp,8) ) + return -EFAULT; + err = do_wrmsr(cpu, reg, data[0], data[1]); + if ( err ) + return err; + tmp += 2; + } + + return ((char *)tmp) - buf; +} + +static int msr_open(struct inode *inode, struct file *file) +{ + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( !(cpu_online_map & (1UL << cpu)) || + !((cpu_data)[cpu].x86_capability & X86_FEATURE_MSR) ) + return -ENXIO; /* No such CPU */ + + MOD_INC_USE_COUNT; + return 0; +} + +static int msr_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * File operations we support + */ +static struct file_operations msr_fops = { + llseek: msr_seek, + read: msr_read, + write: msr_write, + open: msr_open, + release: msr_release, +}; + +int __init msr_init(void) +{ + if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { + printk(KERN_ERR "msr: unable to get major %d for msr\n", + MSR_MAJOR); + return -EBUSY; + } + + return 0; +} + +void __exit msr_exit(void) +{ +} + +module_init(msr_init); +module_exit(msr_exit) + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("H. Peter Anvin "); +MODULE_DESCRIPTION("x86 generic MSR driver"); diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 6a1e10f104d3..3ea101d69358 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -821,8 +821,10 @@ static int __init get_model_name(struct cpuinfo_x86 *c) { unsigned int n, dummy, *v; - /* Actually we must have cpuid or we could never have - * figured out that this was AMD/Cyrix from the vendor info :-). + /* + * Actually we must have cpuid or we could never have + * figured out that this was AMD/Cyrix/Transmeta + * from the vendor info :-). */ cpuid(0x80000000, &n, &dummy, &dummy, &dummy); @@ -1211,6 +1213,86 @@ static void __init centaur_model(struct cpuinfo_x86 *c) sprintf( c->x86_model_id, "WinChip %s", name ); } +static void __init transmeta_model(struct cpuinfo_x86 *c) +{ + unsigned int cap_mask, uk, max, dummy, n, ecx, edx; + unsigned int cms_rev1, cms_rev2; + unsigned int cpu_rev, cpu_freq, cpu_flags; + char cpu_info[65]; + + get_model_name(c); /* Same as AMD/Cyrix */ + + /* Print CMS and CPU revision */ + cpuid(0x80860000, &max, &dummy, &dummy, &dummy); + if ( max >= 0x80860001 ) { + cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); + printk("CPU: Processor revision %u.%u.%u.%u, %u MHz%s%s\n", + (cpu_rev >> 24) & 0xff, + (cpu_rev >> 16) & 0xff, + (cpu_rev >> 8) & 0xff, + cpu_rev & 0xff, + cpu_freq, + (cpu_flags & 1) ? " [recovery]" : "", + (cpu_flags & 2) ? " [longrun]" : ""); + } + if ( max >= 0x80860002 ) { + cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy); + printk("CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n", + (cms_rev1 >> 24) & 0xff, + (cms_rev1 >> 16) & 0xff, + (cms_rev1 >> 8) & 0xff, + cms_rev1 & 0xff, + cms_rev2); + } + if ( max >= 0x80860006 ) { + cpuid(0x80860003, + (void *)&cpu_info[0], + (void *)&cpu_info[4], + (void *)&cpu_info[8], + (void *)&cpu_info[12]); + cpuid(0x80860004, + (void *)&cpu_info[16], + (void *)&cpu_info[20], + (void *)&cpu_info[24], + (void *)&cpu_info[28]); + cpuid(0x80860005, + (void *)&cpu_info[32], + (void *)&cpu_info[36], + (void *)&cpu_info[40], + (void *)&cpu_info[44]); + cpuid(0x80860006, + (void *)&cpu_info[48], + (void *)&cpu_info[52], + (void *)&cpu_info[56], + (void *)&cpu_info[60]); + cpu_info[64] = '\0'; + printk("CPU: %s\n", cpu_info); + } + + /* Unhide possibly hidden flags */ + rdmsr(0x80860004, cap_mask, uk); + wrmsr(0x80860004, ~0, uk); + cpuid(0x00000001, &dummy, &dummy, &dummy, &c->x86_capability); + wrmsr(0x80860004, cap_mask, uk); + + + /* L1/L2 cache */ + cpuid(0x80000000, &n, &dummy, &dummy, &dummy); + + if (n >= 0x80000005) { + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", + ecx>>24, edx>>24); + c->x86_cache_size=(ecx>>24)+(edx>>24); + } + if (n >= 0x80000006) { + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + printk("CPU: L2 Cache: %dK\n", ecx>>16); + c->x86_cache_size=(ecx>>16); + } +} + + void __init get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -1229,6 +1311,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c) c->x86_vendor = X86_VENDOR_NEXGEN; else if (!strcmp(v, "RiseRiseRise")) c->x86_vendor = X86_VENDOR_RISE; + else if (!strcmp(v, "GenuineTMx86")) + c->x86_vendor = X86_VENDOR_TRANSMETA; else c->x86_vendor = X86_VENDOR_UNKNOWN; } @@ -1278,6 +1362,9 @@ static struct cpu_model_info cpu_models[] __initdata = { { X86_VENDOR_RISE, 5, { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + { X86_VENDOR_TRANSMETA, 5, + { NULL, NULL, NULL, "Crusoe", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, }; void __init identify_cpu(struct cpuinfo_x86 *c) @@ -1290,6 +1377,16 @@ void __init identify_cpu(struct cpuinfo_x86 *c) get_cpu_vendor(c); + /* It should be possible for the user to override this. */ + if(c->x86_capability&(1<<18)) { + /* Disable processor serial number */ + unsigned long lo,hi; + rdmsr(0x119,lo,hi); + lo |= 0x200000; + wrmsr(0x119,lo,hi); + printk(KERN_INFO "CPU serial number disabled.\n"); + } + switch (c->x86_vendor) { case X86_VENDOR_UNKNOWN: @@ -1311,16 +1408,6 @@ void __init identify_cpu(struct cpuinfo_x86 *c) return; case X86_VENDOR_INTEL: - if(c->x86_capability&(1<<18)) { - /* Disable processor serial number on Intel Pentium III - from code by Phil Karn */ - unsigned long lo,hi; - rdmsr(0x119,lo,hi); - lo |= 0x200000; - wrmsr(0x119,lo,hi); - printk(KERN_INFO "Pentium-III serial number disabled.\n"); - } - if (c->cpuid_level > 1) { /* supports eax=2 call */ int edx, dummy; @@ -1389,6 +1476,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c) goto name_decoded; break; + + case X86_VENDOR_TRANSMETA: + transmeta_model(c); + return; } @@ -1427,7 +1518,7 @@ void __init dodgy_tsc(void) static char *cpu_vendor_names[] __initdata = { - "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise" }; + "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; void __init print_cpu_info(struct cpuinfo_x86 *c) @@ -1439,7 +1530,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c) else if (c->cpuid_level >= 0) vendor = c->x86_vendor_id; - if (vendor) + if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) printk("%s ", vendor); if (!c->x86_model_id[0]) @@ -1449,6 +1540,8 @@ void __init print_cpu_info(struct cpuinfo_x86 *c) if (c->x86_mask || c->cpuid_level>=0) printk(" stepping %02x\n", c->x86_mask); + else + printk("\n"); } /* @@ -1539,7 +1632,7 @@ int get_cpuinfo(char * buffer) break; default: - /* Unknown CPU manufacturer. Transmeta ? :-) */ + /* Unknown CPU manufacturer or no special handling needed */ break; } diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 9ae16467294c..c35f5bae8358 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -32,6 +32,41 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -493,7 +528,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 7e2986134fa3..0df54449f5dc 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -83,6 +83,20 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ force_sig(signr, tsk); \ } +#define DO_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + die_if_no_fixup(str,regs,error_code); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + force_sig_info(signr, &info, tsk); \ +} + #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ @@ -100,6 +114,28 @@ out: \ unlock_kernel(); \ } +#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + lock_kernel(); \ + if (regs->eflags & VM_MASK) { \ + if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \ + goto out; \ + /* else fall through */ \ + } \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + force_sig_info(signr, &info, tsk); \ + die_if_kernel(str,regs,error_code); \ +out: \ + unlock_kernel(); \ +} + void page_exception(void); asmlinkage void divide_error(void); @@ -262,18 +298,27 @@ static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) } } -DO_VM86_ERROR( 0, SIGFPE, "divide error", divide_error, current) +static inline unsigned long get_cr2(void) +{ + unsigned long address; + + /* get the address */ + __asm__("movl %%cr2,%0":"=r" (address)); + return address; +} + +DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, current, FPE_INTDIV, regs->eip) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds, current) -DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) +DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, current, ILL_ILLOPN, regs->eip) DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available, current) DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, current) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) -DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, current, BUS_ADRALN, get_cr2()) DO_ERROR(18, SIGSEGV, "reserved", reserved, current) DO_VM86_ERROR(19, SIGFPE, "XMM fault", xmm_fault, current) @@ -473,6 +518,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) { unsigned int condition; struct task_struct *tsk = current; + siginfo_t info; __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); @@ -507,7 +553,11 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) /* Ok, finally something we can handle */ tsk->thread.trap_no = 1; tsk->thread.error_code = error_code; - force_sig(SIGTRAP, tsk); + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *)regs->eip; + force_sig_info(SIGTRAP, &info, tsk); return; debug_vm86: @@ -532,9 +582,10 @@ clear_TF: * the correct behaviour even in the presence of the asynchronous * IRQ13 behaviour */ -void math_error(void) +void math_error(void *eip) { struct task_struct * task; + siginfo_t info; /* * Save the info for the exception handler @@ -544,13 +595,52 @@ void math_error(void) save_fpu(task); task->thread.trap_no = 16; task->thread.error_code = 0; - force_sig(SIGFPE, task); + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + switch(((~task->thread.i387.hard.cwd) & + task->thread.i387.hard.swd & 0x3f) | + (task->thread.i387.hard.swd & 0x240)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + case 0x040: /* Stack Fault */ + case 0x240: /* Stack Fault | Direction */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); } asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) { ignore_irq13 = 1; - math_error(); + math_error((void *)regs->eip); } asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 697645988e11..b88c4a422075 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -124,13 +124,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) unsigned long page; unsigned long fixup; int write; - int si_code = SEGV_MAPERR; + siginfo_t info; /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); tsk = current; mm = tsk->mm; + info.si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user @@ -165,9 +166,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) * we can handle it.. */ good_area: + info.si_code = SEGV_ACCERR; write = 0; - si_code = SEGV_ACCERR; - switch (error_code & 3) { default: /* 3: write, present */ #ifdef TEST_VERIFY_AREA @@ -225,14 +225,14 @@ bad_area: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { - struct siginfo si; tsk->thread.cr2 = address; tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; - si.si_signo = SIGSEGV; - si.si_code = si_code; - si.si_addr = (void*) address; - force_sig_info(SIGSEGV, &si, tsk); + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void *)address; + force_sig_info(SIGSEGV, &info, tsk); return; } @@ -309,7 +309,11 @@ do_sigbus: tsk->thread.cr2 = address; tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; - force_sig(SIGBUS, tsk); + info.si_code = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info(SIGBUS, &info, tsk); /* Kernel mode? Handle exceptions or die */ if (!(error_code & 4)) diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index 83e6c9e613f3..e85af6cedcc7 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -48,12 +48,57 @@ struct rt_sigframe_ia32 int sig; int pinfo; int puc; - struct siginfo info; + siginfo_t32 info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8]; }; +static int +copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) +{ + int err; + + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + return -EFAULT; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. + This routine must convert siginfo from 64bit to 32bit as well + at the same time. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + if (from->si_code < 0) + err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); + else { + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_uid, &to->si_uid); + break; + case __SI_FAULT >> 16: + err |= __put_user((long)from->si_addr, &to->si_addr); + break; + case __SI_POLL >> 16: + err |= __put_user(from->si_band, &to->si_band); + err |= __put_user(from->si_fd, &to->si_fd); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + } + return err; +} + + + static int setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, struct pt_regs *regs, unsigned long mask) @@ -283,7 +328,7 @@ setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info, &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user32(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index a0cca9da7a47..25197c1d443a 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -138,6 +138,43 @@ restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt) return err; } +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + case __SI_POLL >> 16: + err |= __put_user(from->si_addr, &to->si_addr); + err |= __put_user(from->si_imm, &to->si_imm); + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * When we get here, ((struct switch_stack *) pt - 1) is a * switch_stack frame that has no defined value. Upon return, we @@ -290,7 +327,7 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, st if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err = __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + err = copy_siginfo_to_user(&frame->info, info); err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp); err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size); diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index d795c71ad5e5..d67617bea0b9 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -189,6 +189,41 @@ struct rt_sigframe }; +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ static inline int restore_fpu_state(struct sigcontext *sc) @@ -877,7 +912,7 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index a912be2e1fb9..6010678d1aed 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -37,6 +37,41 @@ extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); extern asmlinkage int save_fp_context(struct sigcontext *sc); extern asmlinkage int restore_fp_context(struct sigcontext *sc); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -438,7 +473,7 @@ setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, } /* Create siginfo. */ - err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); diff --git a/arch/mips64/kernel/signal.c b/arch/mips64/kernel/signal.c index 7f644a437883..97c54daa090a 100644 --- a/arch/mips64/kernel/signal.c +++ b/arch/mips64/kernel/signal.c @@ -38,6 +38,41 @@ extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); extern asmlinkage int save_fp_context(struct sigcontext *sc); extern asmlinkage int restore_fp_context(struct sigcontext *sc); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + err |= __put_user((long)from->si_addr, &to->si_addr); + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + static inline int store_fp_context(struct sigcontext *sc) { unsigned int fcr0; @@ -466,7 +501,7 @@ setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, } /* Create siginfo. */ - err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 1ca3a65f8e14..e5452fedbe1d 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -58,6 +58,41 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs); extern int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 774359a1be75..14ce2eae9507 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -33,6 +33,41 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -424,7 +459,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index e75d5d000960..e807683ea42a 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -95,6 +95,38 @@ struct rt_signal_frame { __siginfo_fpu_t fpu_state; }; +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + /* case __SI_RT: This is not generated by the kernel as of now. */ + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + break; + } + return err; + } +} + /* Align macros */ #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7))) #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) @@ -710,7 +742,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window)); - err |= __copy_to_user(&sf->info, info, sizeof(siginfo_t)); + err |= copy_siginfo_to_user(&sf->info, info); if (err) goto sigsegv; diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index efd6a64d131c..f893e7f3a504 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -42,6 +42,38 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, /* #define DEBUG_SIGNALS_TRACE 1 */ /* #define DEBUG_SIGNALS_MAPS 1 */ +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + case __SI_FAULT >> 16: + case __SI_POLL >> 16: + err |= __put_user(from->si_trapno, &to->si_trapno); + default: + err |= __put_user(from->si_addr, &to->si_addr); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) { @@ -512,7 +544,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, sizeof(struct reg_window)); if (info) - err |= copy_to_user(&sf->info, info, sizeof(siginfo_t)); + err |= copy_siginfo_to_user(&sf->info, info); else { err |= __put_user(signo, &sf->info.si_signo); err |= __put_user(SI_NOINFO, &sf->info.si_code); diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 1f5c03716102..f908b0636381 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -108,17 +108,21 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) return -EFAULT; + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. + This routine must convert siginfo from 64bit to 32bit as well + at the same time. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); + err |= __put_user((short)from->si_code, &to->si_code); if (from->si_code < 0) err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { - int signo = from->si_signo; - if (from->si_code == SI_USER || from->si_code == SI_KERNEL) - signo = SIGRTMIN; - switch (signo) { - case SIGCHLD: + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); @@ -126,16 +130,12 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; - case SIGURG: - case SIGIO: - case SIGSEGV: - case SIGILL: - case SIGFPE: - case SIGBUS: - case SIGEMT: + case __SI_FAULT >> 16: + case __SI_POLL >> 16: err |= __put_user(from->si_trapno, &to->si_trapno); err |= __put_user((long)from->si_addr, &to->si_addr); break; + /* case __SI_RT: This is not generated by the kernel as of now. */ } } return err; diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 12592b747d6b..db6d2b4d0fd3 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -2052,43 +2052,84 @@ asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize return ret; } -extern asmlinkage int -sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, - const struct timespec *uts, size_t sigsetsize); - asmlinkage int sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, struct timespec32 *uts, __kernel_size_t32 sigsetsize) { - sigset_t s; - sigset_t32 s32; - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); + int ret, sig; + sigset_t these; + sigset_t32 these32; + struct timespec ts; siginfo_t info; - - if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) + long timeout = 0; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user (&these32, uthese, sizeof(sigset_t32))) return -EFAULT; + switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); + case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); + case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); + case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); } + + /* + * Invert the set of allowed signals to get those we + * want to block. + */ + sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); + signotset(&these); + if (uts) { - ret = get_user (t.tv_sec, &uts->tv_sec); - ret |= __get_user (t.tv_nsec, &uts->tv_nsec); - if (ret) - return -EFAULT; + if (get_user (ts.tv_sec, &uts->tv_sec) || + get_user (ts.tv_nsec, &uts->tv_nsec)) + return -EINVAL; + if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 + || ts.tv_sec < 0) + return -EINVAL; } - set_fs (KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); - set_fs (old_fs); - if (ret >= 0 && uinfo) { - extern int copy_siginfo_to_user32(siginfo_t32 *, siginfo_t *); - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; + + spin_lock_irq(¤t->sigmask_lock); + sig = dequeue_signal(&these, &info); + if (!sig) { + /* None ready -- temporarily unblock those we're interested + in so that we'll be awakened when they arrive. */ + sigset_t oldblocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &these); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + timeout = MAX_SCHEDULE_TIMEOUT; + if (uts) + timeout = (timespec_to_jiffies(&ts) + + (ts.tv_sec || ts.tv_nsec)); + + current->state = TASK_INTERRUPTIBLE; + timeout = schedule_timeout(timeout); + + spin_lock_irq(¤t->sigmask_lock); + sig = dequeue_signal(&these, &info); + current->blocked = oldblocked; + recalc_sigpending(current); } + spin_unlock_irq(¤t->sigmask_lock); + + if (sig) { + ret = sig; + if (uinfo) { + if (copy_siginfo_to_user32(uinfo, &info)) + ret = -EFAULT; + } + } else { + ret = -EAGAIN; + if (timeout) + ret = -EINTR; + } + return ret; } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 8e4c359c75fe..afb9e7bc4b3e 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -757,15 +757,6 @@ end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -static inline void buffer_IO_error(struct buffer_head * bh) -{ - mark_buffer_clean(bh); - /* - * b_end_io has to clear the BH_Uptodate bitflag in the error case! - */ - bh->b_end_io(bh, 0); -} - int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { unsigned long flags; diff --git a/drivers/block/lvm-snap.c b/drivers/block/lvm-snap.c index 77500cc43c69..2f01d3f7b16e 100644 --- a/drivers/block/lvm-snap.c +++ b/drivers/block/lvm-snap.c @@ -278,12 +278,12 @@ int lvm_snapshot_COW(kdev_t org_phys_dev, lvm_hash_link(lv_snap->lv_block_exception + idx, org_phys_dev, org_start, lv_snap); lv_snap->lv_remap_ptr = idx + 1; - return 0; + return 1; /* slow path */ out: lvm_drop_snapshot(lv_snap, reason); - return 1; + return -1; fail_out_of_space: reason = "out of space"; diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c index df9bba37be90..f5c2bb1e41b7 100644 --- a/drivers/block/lvm.c +++ b/drivers/block/lvm.c @@ -122,7 +122,7 @@ * - avoided "/dev/" in proc filesystem output * - avoided inline strings functions lvm_strlen etc. * 14/02/2000 - support for 2.3.43 - * - integrated Andrea Arcagnelli's snapshot code + * - integrated Andrea Arcangeli's snapshot code * */ @@ -171,9 +171,9 @@ static char *lvm_short_version = "version 0.8final (15/02/2000)"; #include #include -#define LVM_CORRECT_READ_AHEAD( a) \ - if ( a < LVM_MIN_READ_AHEAD || \ - a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; +#define LVM_CORRECT_READ_AHEAD(a) \ + (((a) < LVM_MIN_READ_AHEAD || (a) > LVM_MAX_READ_AHEAD) \ + ? LVM_MAX_READ_AHEAD : (a)) #ifndef WRITEA # define WRITEA WRITE @@ -193,13 +193,11 @@ static void lvm_dummy_device_request(request_queue_t *); #define DEVICE_REQUEST lvm_dummy_device_request static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); +static void lvm_plug_device_noop(request_queue_t *, kdev_t); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); -static ssize_t lvm_blk_read(struct file *, char *, size_t, loff_t *); -static ssize_t lvm_blk_write(struct file *, const char *, size_t, loff_t *); - static int lvm_chr_open(struct inode *, struct file *); static int lvm_chr_close(struct inode *, struct file *); @@ -298,7 +296,6 @@ static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; static struct file_operations lvm_chr_fops = { @@ -307,18 +304,6 @@ static struct file_operations lvm_chr_fops = ioctl: lvm_chr_ioctl, }; -static struct file_operations lvm_blk_fops = -{ - open: lvm_blk_open, - release: blkdev_close, - read: lvm_blk_read, - write: lvm_blk_write, - ioctl: lvm_blk_ioctl, - fsync: block_fsync, -}; - -#define BLOCK_DEVICE_OPERATIONS -/* block device operations structure needed for 2.3.38? and above */ static struct block_device_operations lvm_blk_dops = { open: lvm_blk_open, @@ -370,11 +355,7 @@ int __init lvm_init(void) printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); return -EIO; } -#ifdef BLOCK_DEVICE_OPERATIONS if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) -#else - if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0) -#endif { printk("%s -- register_blkdev failed\n", lvm_name); if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) @@ -410,6 +391,7 @@ int __init lvm_init(void) blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); + blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_plug_device_noop); /* optional read root VGDA */ /* if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg); @@ -488,8 +470,6 @@ void __init lvm_init_vars(void) loadtime = CURRENT_TIME; - lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; - pe_lock_req.lock = UNLOCK_PE; pe_lock_req.data.lv_dev = \ pe_lock_req.data.pv_dev = \ @@ -724,8 +704,19 @@ static int lvm_chr_ioctl(struct inode *inode, struct file *file, sizeof(pv_flush_req)) != 0) return -EFAULT; - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); + for ( v = 0; v < ABS_MAX_VG; v++) { + unsigned int p; + if ( vg[v] == NULL) continue; + for ( p = 0; p < vg[v]->pv_max; p++) { + if ( vg[v]->pv[p] != NULL && + strcmp ( vg[v]->pv[p]->pv_name, + pv_flush_req.pv_name) == 0) { + fsync_dev ( vg[v]->pv[p]->pv_dev); + invalidate_buffers ( vg[v]->pv[p]->pv_dev); + return 0; + } + } + } return 0; default: @@ -813,10 +804,6 @@ static int lvm_blk_open(struct inode *inode, struct file *file) if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; } -#ifdef BLOCK_DEVICE_OPERATIONS - file->f_op = &lvm_blk_fops; -#endif - /* be sure to increment VG counter */ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; lv_ptr->lv_open++; @@ -836,34 +823,6 @@ static int lvm_blk_open(struct inode *inode, struct file *file) } /* lvm_blk_open() */ -/* - * block device read - */ -static ssize_t lvm_blk_read(struct file *file, char *buffer, - size_t size, loff_t * offset) -{ - int minor = MINOR(file->f_dentry->d_inode->i_rdev); - - read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] = - vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; - return block_read(file, buffer, size, offset); -} - - -/* - * block device write - */ -static ssize_t lvm_blk_write(struct file *file, const char *buffer, - size_t size, loff_t * offset) -{ - int minor = MINOR(file->f_dentry->d_inode->i_rdev); - - read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] = - vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; - return block_write(file, buffer, size, offset); -} - - /* * block device i/o-control routine */ @@ -906,6 +865,7 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); #endif fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); break; @@ -921,7 +881,7 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, if ((long) arg < LVM_MIN_READ_AHEAD || (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL; - lv_ptr->lv_read_ahead = (long) arg; + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = (long) arg; break; @@ -1293,7 +1253,6 @@ static int lvm_proc_get_info(char *page, char **start, off_t pos, int count) static int lvm_map(struct buffer_head *bh, int rw) { int minor = MINOR(bh->b_rdev); - int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; @@ -1308,7 +1267,7 @@ static int lvm_map(struct buffer_head *bh, int rw) printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", lvm_name, lv->lv_name); - return -1; + goto error; } /* if ( lv->lv_access & LV_SNAPSHOT) @@ -1323,7 +1282,7 @@ static int lvm_map(struct buffer_head *bh, int rw) (rw == WRITEA || rw == WRITE)) { printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d] b_blocknr: %lu b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector); - return 0; + goto error; } if ((rw == WRITE || rw == WRITEA) && @@ -1331,7 +1290,7 @@ static int lvm_map(struct buffer_head *bh, int rw) printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", lvm_name, lv->lv_name); - return -1; + goto error; } #ifdef DEBUG_MAP printk(KERN_DEBUG @@ -1347,7 +1306,7 @@ static int lvm_map(struct buffer_head *bh, int rw) printk(KERN_ALERT "%s - lvm_map *rsector: %lu or size: %lu wrong for" " minor: %2d\n", lvm_name, rsector_tmp, size, minor); - return -1; + goto error; } rsector_sav = rsector_tmp; rdev_sav = rdev_tmp; @@ -1444,11 +1403,11 @@ lvm_second_remap: pe_start, lv_ptr)) { /* create a new mapping */ - ret = lvm_snapshot_COW(rdev_tmp, - rsector_tmp, - pe_start, - rsector_sav, - lv_ptr); + lvm_snapshot_COW(rdev_tmp, + rsector_tmp, + pe_start, + rsector_sav, + lv_ptr); } rdev_tmp = rdev_sav; rsector_tmp = rsector_sav; @@ -1467,7 +1426,11 @@ lvm_second_remap: bh->b_rdev = rdev_tmp; bh->b_rsector = rsector_tmp; - return ret; + return 1; + + error: + buffer_IO_error(bh); + return -1; } /* lvm_map() */ @@ -1519,6 +1482,12 @@ static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *b return 1; } +/* + * plug device function is a noop because plugging has to happen + * in the queue of the physical blockdevice to allow the + * elevator to do a better job. + */ +static void lvm_plug_device_noop(request_queue_t *q, kdev_t dev) { } /******************************************************************** * @@ -2090,7 +2059,7 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; - LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; @@ -2328,7 +2297,7 @@ static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; /* vg_lv_map array doesn't have to be changed here */ - LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); lv_ptr->lv_status = lv_status_save; return 0; diff --git a/drivers/block/md.c b/drivers/block/md.c index 1af15fd051f5..883c2f7795e3 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -220,8 +220,7 @@ static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) if (mddev && mddev->pers) return mddev->pers->make_request(q, mddev, rw, bh); else { - mark_buffer_clean(bh); - bh->b_end_io(bh, 0); + buffer_IO_error(bh); return -1; } } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 5308e95fd2e8..b78d88ef7c43 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -666,10 +666,12 @@ static void __init rd_load_image(kdev_t device, int offset, int unit) } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos); +#if !defined(CONFIG_ARCH_S390) if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); rotate++; } +#endif } printk("done.\n"); kfree(buf); diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index fe0d33a77ec5..767a52dcb371 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -1727,7 +1727,8 @@ int __init aztcd_init(void) return -EIO; } - for (count = 0; count < AZT_TIMEOUT; count++); + for (count = 0; count < AZT_TIMEOUT; count++) + barrier(); /* Stop gcc 2.96 being smart */ if ((st=getAztStatus())==-1) { printk("aztcd: Drive Status Error Status=%x\n",st); diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index b17efd42963d..dd9ca78c6fb7 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -276,7 +276,7 @@ static void * rvmalloc(signed long size) void * mem; unsigned long adr, page; - mem=vmalloc(size); + mem=vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ diff --git a/drivers/char/cpia.c b/drivers/char/cpia.c index 7145a2061a83..e65b8ec25a90 100644 --- a/drivers/char/cpia.c +++ b/drivers/char/cpia.c @@ -230,7 +230,7 @@ static void *rvmalloc(unsigned long size) size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem = vmalloc(size); + mem = vmalloc_32(size); if (!mem) return NULL; diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 24a4948b55d1..15a24851f8f6 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1028,7 +1028,7 @@ void sx_transmit_chars (struct sx_port *port) if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) c = SERIAL_XMIT_SIZE - port->gs.xmit_tail; - sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n", + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%ld) \n", c, SERIAL_XMIT_SIZE- port->gs.xmit_tail); /* If for one reason or another, we can't copy more data, we're done! */ diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index 80d001468024..d8cc9b2c0508 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -189,7 +189,7 @@ static int evt_q_len = 0; * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */ -static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; +static struct semaphore i2o_configuration_lock; /* * Event spinlock. Used to keep event queue sane and from @@ -215,7 +215,7 @@ static struct notifier_block i2o_reboot_notifier = /* * I2O Core reply handler */ -void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, +static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) { u32 *msg=(u32 *)m; @@ -297,29 +297,44 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, return; } -/* +/** + * i2o_install_handler - install a message handler + * @h: Handler structure + * * Install an I2O handler - these handle the asynchronous messaging - * from the card once it has initialised. + * from the card once it has initialised. If the table of handlers is + * full then -ENOSPC is returned. On a success 0 is returned and the + * context field is set by the function. The structure is part of the + * system from this time onwards. It must not be freed until it has + * been uninstalled */ int i2o_install_handler(struct i2o_handler *h) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;icontext = i; i2o_handlers[i]=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOSPC; } +/** + * i2o_remove_handler - remove an i2o message handler + * @h: handler + * + * Remove a message handler previously installed with i2o_install_handler. + * After this function returns the handler object can be freed or re-used + */ + int i2o_remove_handler(struct i2o_handler *h) { i2o_handlers[h->context]=NULL; @@ -332,12 +347,24 @@ int i2o_remove_handler(struct i2o_handler *h) * Each device has a pointer to it's LCT entry to be used * for fun purposes. */ + +/** + * i2o_install_device - attach a device to a controller + * @c: controller + * @d: device + * + * Add a new device to an i2o controller. This can be called from + * non interrupt contexts only. It adds the device and marks it as + * unclaimed. The device memory becomes part of the kernel and must + * be uninstalled before being freed or reused. Zero is returned + * on success. + */ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; @@ -347,7 +374,7 @@ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } @@ -411,11 +438,22 @@ int __i2o_delete_device(struct i2o_device *d) return -EINVAL; } +/** + * i2o_delete_device - remove an i2o device + * @d: device to remove + * + * This function unhooks a device from a controller. The device + * will not be unhooked if it has an owner who does not wish to free + * it, or if the owner lacks a dev_del_notify function. In that case + * -EBUSY is returned. On success 0 is returned. Other errors cause + * negative errno values to be returned + */ + int i2o_delete_device(struct i2o_device *d) { int ret; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); /* * Seek, locate @@ -423,23 +461,37 @@ int i2o_delete_device(struct i2o_device *d) ret = __i2o_delete_device(d); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return ret; } -/* - * Add and remove controllers from the I2O controller list +/** + * i2o_install_controller - attach a controller + * @c: controller + * + * Add a new controller to the i2o layer. This can be called from + * non interrupt contexts only. It adds the controller and marks it as + * unused with no devices. If the tables are full or memory allocations + * fail then a negative errno code is returned. On success zero is + * returned and the controller is bound to the system. The structure + * must not be freed or reused until being uninstalled. */ int i2o_install_controller(struct i2o_controller *c) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;idlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); + if(c->dlct==NULL) + { + up(&i2o_configuration_lock); + return -ENOMEM; + } i2o_controllers[i]=c; c->devices = NULL; c->next=i2o_controller_chain; @@ -448,20 +500,28 @@ int i2o_install_controller(struct i2o_controller *c) c->page_frame = NULL; c->hrt = NULL; c->lct = NULL; - c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); c->status_block = NULL; sprintf(c->name, "i2o/iop%d", i); i2o_num_controllers++; init_MUTEX_LOCKED(&c->lct_sem); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } printk(KERN_ERR "No free i2o controller slots.\n"); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } +/** + * i2o_delete_controller - delete a controller + * @c: controller + * + * Remove an i2o controller from the system. If the controller or its + * devices are busy then -EBUSY is returned. On a failure a negative + * errno code is returned. On success zero is returned. + */ + int i2o_delete_controller(struct i2o_controller *c) { struct i2o_controller **p; @@ -477,12 +537,12 @@ int i2o_delete_controller(struct i2o_controller *c) if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) i2o_event_register(c, core_context, 0, 0, 0); - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, c->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } while(c->devices) @@ -491,7 +551,7 @@ int i2o_delete_controller(struct i2o_controller *c) { /* Shouldnt happen */ c->bus_disable(c); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } } @@ -528,7 +588,7 @@ int i2o_delete_controller(struct i2o_controller *c) c->destructor(c); *p=c->next; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); if(c->page_frame) kfree(c->page_frame); @@ -551,16 +611,33 @@ int i2o_delete_controller(struct i2o_controller *c) } p=&((*p)->next); } - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); return -ENOENT; } +/** + * i2o_unlock_controller - unlock a controller + * @c: controller to unlock + * + * Take a lock on an i2o controller. This prevents it being deleted. + * i2o controllers are not refcounted so a deletion of an in use device + * will fail, not take affect on the last dereference. + */ + void i2o_unlock_controller(struct i2o_controller *c) { atomic_dec(&c->users); } +/** + * i2o_find_controller - return a locked controller + * @n: controller number + * + * Returns a pointer to the controller object. The controller is locked + * on return. NULL is returned if the controller is not found. + */ + struct i2o_controller *i2o_find_controller(int n) { struct i2o_controller *c; @@ -568,17 +645,28 @@ struct i2o_controller *i2o_find_controller(int n) if(n<0 || n>=MAX_I2O_CONTROLLERS) return NULL; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); c=i2o_controllers[n]; if(c!=NULL) atomic_inc(&c->users); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return c; } -/* - * Issue UTIL_CLAIM or UTIL_RELEASE message +/** + * i2o_issue_claim - claim or release a device + * @cmd: command + * @c: controller to claim for + * @tid: i2o task id + * @type: type of claim + * + * Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent + * is set by cmd. The tid is the task id of the object to claim and the + * type is the claim type (see the i2o standard) + * + * Zero is returned on success. */ + static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) { u32 msg[5]; @@ -592,54 +680,70 @@ static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) } /* - * Claim a device for use by an OSM + * i2o_claim_device - claim a device for use by an OSM + * @d: device to claim + * @h: handler for this device + * + * Do the leg work to assign a device to a given OSM on Linux. The + * kernel updates the internal handler data for the device and then + * performs an I2O claim for the device, attempting to claim the + * device as primary. If the attempt fails a negative errno code + * is returned. On success zero is returned. */ + int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) { - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if (d->owner) { printk(KERN_INFO "Device claim called, but dev allready owned by %s!", h->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } + d->owner=h; if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, I2O_CLAIM_PRIMARY)) { - spin_unlock(&i2o_configuration_lock); + d->owner = NULL; return -EBUSY; } - - d->owner=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } -/* - * Release a device that the OSM is using +/** + * i2o_release_device - release a device that the OSM is using + * @d: device to claim + * @h: handler for this device + * + * Drop a claim by an OSM on a given I2O device. The handler is cleared + * and 0 is returned on success. + * */ + int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if (d->owner != h) { printk(KERN_INFO "Claim release called, but not owned by %s!", h->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOENT; } + d->owner = NULL; + if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) { err = -ENXIO; + d->owner = h; } - d->owner = NULL; - - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return err; } @@ -994,7 +1098,10 @@ static int i2o_dyn_lct(void *foo) return 0; } -/* +/** + * i2o_run_queue - process pending events on a controller + * @c: controller to process + * * This is called by the bus specific driver layer when an interrupt * or poll of this card interface is desired. */ @@ -1046,9 +1153,13 @@ void i2o_run_queue(struct i2o_controller *c) } -/* - * Do i2o class name lookup +/** + * i2o_get_class_name - do i2o class name lookup + * @class: class number + * + * Return a descriptive string for an i2o class */ + const char *i2o_get_class_name(int class) { int idx = 16; @@ -1112,8 +1223,18 @@ const char *i2o_get_class_name(int class) } -/* - * Wait up to 5 seconds for a message slot to be available. +/** + * i2o_wait_message + * @c: controller + * @why: explanation + * + * This function waits up to 5 seconds for a message slot to be + * available. If no message is available it prints an error message + * that is expected to be what the message will be used for (eg + * "get_status"). 0xFFFFFFFF is returned on a failure. + * + * On a success the message is returned. This is the physical page + * frame offset address from the read port. (See the i2o spec) */ u32 i2o_wait_message(struct i2o_controller *c, char *why) @@ -1134,8 +1255,14 @@ u32 i2o_wait_message(struct i2o_controller *c, char *why) return m; } -/* - * Dump the information block associated with a given unit (TID) +/** + * i2o_report_controller_unit - print information about a tid + * @c: controller + * @d: device + * + * Dump an information block associated with a given unit (TID). The + * tables are read and a block of text is output to printk that is + * formatted intended for the user. */ void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) @@ -1341,10 +1468,14 @@ static int i2o_parse_lct(struct i2o_controller *c) } -/* - * Quiesce IOP. Causes IOP to make external operation quiescend. - * Internal operation of the IOP continues normally. +/** + * i2o_quiesce_controller - quiesce controller + * @c: controller + * + * Quiesce an IOP. Causes IOP to make external operation quiescent + * (i2o 'READY' state). Internal operation of the IOP continues normally. */ + int i2o_quiesce_controller(struct i2o_controller *c) { u32 msg[4]; @@ -1373,14 +1504,18 @@ int i2o_quiesce_controller(struct i2o_controller *c) dprintk(KERN_INFO "%s: Quiesced.\n", c->name); i2o_status_get(c); // Entered READY state - - return ret; - + return ret; } -/* - * Enable IOP. Allows the IOP to resume external operations. +/** + * i2o_enable_controller - move controller from ready to operational + * @c: controller + * + * Enable IOP. This allows the IOP to resume external operations and + * reverses the effect of a quiesce. In the event of an error a negative + * errno code is returned. */ + int i2o_enable_controller(struct i2o_controller *c) { u32 msg[4]; @@ -1395,7 +1530,7 @@ int i2o_enable_controller(struct i2o_controller *c) msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - /* How long of a timeout do we need? */ + /* How long of a timeout do we need? */ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) printk(KERN_ERR "%s: Could not enable (status=%#x).\n", @@ -1408,12 +1543,16 @@ int i2o_enable_controller(struct i2o_controller *c) return ret; } -/* - * Clear an IOP to HOLD state, ie. terminate external operations, clear all - * input queues and prepare for a system restart. IOP's internal operation - * continues normally and the outbound queue is alive. - * IOP is not expected to rebuild its LCT. +/** + * i2o_clear_controller - clear a controller + * @c: controller + * + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. + * The IOP is not expected to rebuild its LCT. */ + int i2o_clear_controller(struct i2o_controller *c) { struct i2o_controller *iop; @@ -1447,12 +1586,16 @@ int i2o_clear_controller(struct i2o_controller *c) } -/* - * Reset the IOP into INIT state and wait until IOP gets into RESET state. - * Terminate all external operations, clear IOP's inbound and outbound - * queues, terminate all DDMs, and reload the IOP's operating environment - * and all local DDMs. IOP rebuilds its LCT. +/** + * i2o_reset_controller + * @c: controller to reset + * + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment + * and all local DDMs. The IOP rebuilds its LCT. */ + static int i2o_reset_controller(struct i2o_controller *c) { struct i2o_controller *iop; @@ -1556,9 +1699,16 @@ static int i2o_reset_controller(struct i2o_controller *c) } -/* - * Get the status block for the IOP +/** + * i2o_status_get - get the status block for the IOP + * @c: controller + * + * Issue a status query on the controller. This updates the + * attached status_block. If the controller fails to reply or an + * error occurs then a negative errno code is returned. On success + * zero is returned and the status_blok is updated. */ + int i2o_status_get(struct i2o_controller *c) { long time; @@ -1743,7 +1893,7 @@ static int i2o_systab_send(struct i2o_controller *iop) /* * Initialize I2O subsystem. */ -static void __init i2o_sys_init() +static void __init i2o_sys_init(void) { struct i2o_controller *iop, *niop = NULL; @@ -1806,9 +1956,13 @@ rebuild_sys_tab: } } -/* - * Shutdown I2O system +/** + * i2o_sys_shutdown - shutdown I2O system + * + * Bring down each i2o controller and then return. Each controller + * is taken through an orderly shutdown */ + static void i2o_sys_shutdown(void) { struct i2o_controller *iop, *niop; @@ -1822,9 +1976,16 @@ static void i2o_sys_shutdown(void) } } -/* - * Bring an I2O controller into HOLD state. See the spec. +/** + * i2o_activate_controller - bring controller up to HOLD + * @iop: controller + * + * This function brings an I2O controller into HOLD state. The adapter + * is reset if neccessary and then the queues and resource table + * are read. -1 is returned on a failure, 0 on success. + * */ + int i2o_activate_controller(struct i2o_controller *iop) { /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ @@ -1872,9 +2033,14 @@ int i2o_activate_controller(struct i2o_controller *iop) } -/* - * Clear and (re)initialize IOP's outbound queue +/** + * i2o_init_outbound_queue - setup the outbound queue + * @c: controller + * + * Clear and (re)initialize IOP's outbound queue. Returns 0 on + * success or a negative errno code on a failure. */ + int i2o_init_outbound_q(struct i2o_controller *c) { u8 *status; @@ -1938,6 +2104,15 @@ int i2o_init_outbound_q(struct i2o_controller *c) return 0; } +/** + * i2o_post_outbound_messages - fill message queue + * @c: controller + * + * Allocate a message frame and load the messages into the IOP. The + * function returns zero on success or a negative errno code on + * failure. + */ + int i2o_post_outbound_messages(struct i2o_controller *c) { int i; @@ -3071,6 +3246,9 @@ extern int i2o_scsi_init(void); int __init i2o_init(void) { printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); + + init_MUTEX(&i2o_configuration_lock); + if (i2o_install_handler(&i2o_core_handler) < 0) { printk(KERN_ERR diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index cf49e1a66c26..d193135f5571 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -100,7 +100,7 @@ static int pnp_ide_dev_idx = 0; /* * Probe for ISA PnP IDE interfaces. */ -void pnpide_init(int enable) +void __init pnpide_init(int enable) { struct pci_dev *dev = NULL; struct pnp_dev_t *dev_type; diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 11fa4c6dea62..428f0cabd0bc 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1092,6 +1092,7 @@ dgrs_download(struct net_device *dev0) for (i = jiffies + 8 * HZ; time_after(i, jiffies); ) { + barrier(); /* Gcc 2.95 needs this */ if (priv0->bcomm->bc_status >= BC_RUN) break; } diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 4eeeae9aab18..9adaf86a4a0a 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -2932,7 +2932,10 @@ 1277 Comstream 1278 Transtech Parallel Systems Ltd. 1279 Transmeta Corporation - 0295 Virtual Northbridge + 0295 Northbridge + 0395 LongRun Northbridge + 0396 SDRAM controller + 0397 BIOS scratchpad 127a Rockwell International 1002 HCF 56k V90 FaxModem 127a 1002 HCF 56k V90 Modem diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c index c083f2982326..f643dee4751c 100644 --- a/drivers/usb/ibmcam.c +++ b/drivers/usb/ibmcam.c @@ -243,7 +243,7 @@ static void *rvmalloc(unsigned long size) size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem = vmalloc(size); + mem = vmalloc_32(size); if (!mem) return NULL; diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c index 73a54a7b2039..3ffb6f8eb3dc 100644 --- a/drivers/usb/ov511.c +++ b/drivers/usb/ov511.c @@ -216,7 +216,7 @@ static void *rvmalloc(unsigned long size) size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem = vmalloc(size); + mem = vmalloc_32(size); if (!mem) return NULL; diff --git a/drivers/video/Config.in b/drivers/video/Config.in index c0482cd4053e..edc971196866 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -220,7 +220,8 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ - "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ + "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -236,7 +237,7 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" ]; then + "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi fi @@ -250,7 +251,8 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ + "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -262,7 +264,7 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" ]; then + "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -288,7 +290,7 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ - "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -297,7 +299,7 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_ATY128" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" ]; then + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB32 m fi fi diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 244ff5872ef2..4908aebf2fad 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o +obj-$(CONFIG_FB_SIS) += sisfb.o ifeq ($(CONFIG_FB_MATROX),y) SUB_DIRS += matrox diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 034ff8c1fedb..88eda6d6f82b 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -111,6 +111,8 @@ extern int rivafb_init(void); extern int rivafb_setup(char*); extern int tdfxfb_init(void); extern int tdfxfb_setup(char*); +extern int sisfb_init(void); +extern int sisfb_setup(char*); static struct { const char *name; @@ -235,6 +237,9 @@ static struct { /* Must be last to avoid that vfb becomes your primary display */ { "vfb", vfb_init, vfb_setup }, #endif +#ifdef CONFIG_FB_SIS + { "sisfb", sisfb_init, sisfb_setup }, +#endif }; #define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers)) diff --git a/drivers/video/sisfb.c b/drivers/video/sisfb.c new file mode 100644 index 000000000000..bace20cd4af9 --- /dev/null +++ b/drivers/video/sisfb.c @@ -0,0 +1,2982 @@ +/* + * SiS 300/630/540 frame buffer device For Kernal 2.3.x + * + * This driver is partly based on the VBE 2.0 compliant graphic + * boards framebuffer driver, which is + * + * (c) 1998 Gerd Knorr + * + */ + +#define EXPORT_SYMTAB +#undef SISFBDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include