diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-06-26 22:19:40 +0100 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-06-26 22:19:40 +0100 |
commit | 2a322e4c08be4e7cb0c04b427ddaaa679fd88863 (patch) | |
tree | ad8cc17bfd3b5e57e36f07a249028667d72f0b96 | |
parent | ba6d2377c85c9b8a793f455d8c9b6cf31985d70f (diff) | |
parent | 8678887e7fb43cd6c9be6c9807b05e77848e0920 (diff) | |
download | op-kernel-dev-2a322e4c08be4e7cb0c04b427ddaaa679fd88863.zip op-kernel-dev-2a322e4c08be4e7cb0c04b427ddaaa679fd88863.tar.gz |
Automatic merge with /usr/src/ntfs-2.6.git.
637 files changed, 14364 insertions, 7123 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 8de8a01..f28a24e 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -138,6 +138,8 @@ java.txt - info on the in-kernel binary support for Java(tm). kbuild/ - directory with info about the kernel build process. +kdumpt.txt + - mini HowTo on getting the crash dump code to work. kernel-doc-nano-HOWTO.txt - mini HowTo on generation and location of kernel documentation files. kernel-docs.txt diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 4d35562..4d1f41b 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -132,21 +132,6 @@ which require discussion or do not have a clear advantage should usually be sent first to linux-kernel. Only after the patch is discussed should the patch then be submitted to Linus. -For small patches you may want to CC the Trivial Patch Monkey -trivial@rustcorp.com.au set up by Rusty Russell; which collects "trivial" -patches. Trivial patches must qualify for one of the following rules: - Spelling fixes in documentation - Spelling fixes which could break grep(1). - Warning fixes (cluttering with useless warnings is bad) - Compilation fixes (only if they are actually correct) - Runtime fixes (only if they actually fix things) - Removing use of deprecated functions/macros (eg. check_region). - Contact detail and documentation fixes - Non-portable code replaced by portable code (even in arch-specific, - since people copy, as long as it's trivial) - Any fix by the author/maintainer of the file. (ie. patch monkey - in re-transmission mode) - 5) Select your CC (e-mail carbon copy) list. @@ -299,7 +284,7 @@ can certify the below: then you just add a line saying - Signed-off-by: Random J Developer <random@developer.org> + Signed-off-by: Random J Developer <random@developer.example.org> Some people also put extra tags at the end. They'll just be ignored for now, but you can do this to mark internal company procedures or just diff --git a/Documentation/cdrom/sbpcd b/Documentation/cdrom/sbpcd index d1825df..b3ba63f 100644 --- a/Documentation/cdrom/sbpcd +++ b/Documentation/cdrom/sbpcd @@ -419,6 +419,7 @@ into the file "track01": */ #include <stdio.h> #include <sys/ioctl.h> +#include <sys/types.h> #include <linux/cdrom.h> static struct cdrom_tochdr hdr; @@ -429,7 +430,7 @@ static int datafile, drive; static int i, j, limit, track, err; static char filename[32]; -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { /* * open /dev/cdrom @@ -516,6 +517,7 @@ entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300; } arg.addr.lba++; } + return 0; } /*===================== end program ========================================*/ @@ -564,15 +566,16 @@ Appendix -- the "cdtester" utility: #include <stdio.h> #include <malloc.h> #include <sys/ioctl.h> +#include <sys/types.h> #include <linux/cdrom.h> #ifdef AZT_PRIVATE_IOCTLS #include <linux/../../drivers/cdrom/aztcd.h> -#endif AZT_PRIVATE_IOCTLS +#endif /* AZT_PRIVATE_IOCTLS */ #ifdef SBP_PRIVATE_IOCTLS #include <linux/../../drivers/cdrom/sbpcd.h> #include <linux/fs.h> -#endif SBP_PRIVATE_IOCTLS +#endif /* SBP_PRIVATE_IOCTLS */ struct cdrom_tochdr hdr; struct cdrom_tochdr tocHdr; @@ -590,7 +593,7 @@ union struct cdrom_msf msf; unsigned char buf[CD_FRAMESIZE_RAW]; } azt; -#endif AZT_PRIVATE_IOCTLS +#endif /* AZT_PRIVATE_IOCTLS */ int i, i1, i2, i3, j, k; unsigned char sequence=0; unsigned char command[80]; @@ -738,7 +741,7 @@ void display(int size,unsigned char *buffer) } } -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { printf("\nTesting tool for a CDROM driver's audio functions V0.1\n"); printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n"); @@ -1046,12 +1049,13 @@ main(int argc, char *argv[]) rc=ioctl(drive,CDROMAUDIOBUFSIZ,j); printf("%d frames granted.\n",rc); break; -#endif SBP_PRIVATE_IOCTLS +#endif /* SBP_PRIVATE_IOCTLS */ default: printf("unknown command: \"%s\".\n",command); break; } } + return 0; } /*==========================================================================*/ diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index b85481a..933fae7 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -9,6 +9,7 @@ Dominik Brodowski <linux@brodo.de> + some additions and corrections by Nico Golde <nico@ngolde.de> @@ -25,6 +26,7 @@ Contents: 2.1 Performance 2.2 Powersave 2.3 Userspace +2.4 Ondemand 3. The Governor Interface in the CPUfreq Core @@ -86,7 +88,7 @@ highest frequency within the borders of scaling_min_freq and scaling_max_freq. -2.1 Powersave +2.2 Powersave ------------- The CPUfreq governor "powersave" sets the CPU statically to the @@ -94,7 +96,7 @@ lowest frequency within the borders of scaling_min_freq and scaling_max_freq. -2.2 Userspace +2.3 Userspace ------------- The CPUfreq governor "userspace" allows the user, or any userspace @@ -103,6 +105,14 @@ by making a sysfs file "scaling_setspeed" available in the CPU-device directory. +2.4 Ondemand +------------ + +The CPUfreq govenor "ondemand" sets the CPU depending on the +current usage. To do this the CPU must have the capability to +switch the frequency very fast. + + 3. The Governor Interface in the CPUfreq Core ============================================= diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index 2f8f24e..ad944c0 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -51,6 +51,14 @@ mems_allowed vector. If a cpuset is cpu or mem exclusive, no other cpuset, other than a direct ancestor or descendent, may share any of the same CPUs or Memory Nodes. +A cpuset that is cpu exclusive has a sched domain associated with it. +The sched domain consists of all cpus in the current cpuset that are not +part of any exclusive child cpusets. +This ensures that the scheduler load balacing code only balances +against the cpus that are in the sched domain as defined above and not +all of the cpus in the system. This removes any overhead due to +load balancing code trying to pull tasks outside of the cpu exclusive +cpuset only to be prevented by the tasks' cpus_allowed mask. User level code may create and destroy cpusets by name in the cpuset virtual file system, manage the attributes and permissions of these @@ -84,6 +92,9 @@ This can be especially valuable on: and a database), or * NUMA systems running large HPC applications with demanding performance characteristics. + * Also cpu_exclusive cpusets are useful for servers running orthogonal + workloads such as RT applications requiring low latency and HPC + applications that are throughput sensitive These subsets, or "soft partitions" must be able to be dynamically adjusted, as the job mix changes, without impacting other concurrently @@ -125,6 +136,8 @@ Cpusets extends these two mechanisms as follows: - A cpuset may be marked exclusive, which ensures that no other cpuset (except direct ancestors and descendents) may contain any overlapping CPUs or Memory Nodes. + Also a cpu_exclusive cpuset would be associated with a sched + domain. - You can list all the tasks (by pid) attached to any cpuset. The implementation of cpusets requires a few, simple hooks @@ -136,6 +149,9 @@ into the rest of the kernel, none in performance critical paths: allowed in that tasks cpuset. - in sched.c migrate_all_tasks(), to keep migrating tasks within the CPUs allowed by their cpuset, if possible. + - in sched.c, a new API partition_sched_domains for handling + sched domain changes associated with cpu_exclusive cpusets + and related changes in both sched.c and arch/ia64/kernel/domain.c - in the mbind and set_mempolicy system calls, to mask the requested Memory Nodes by what's allowed in that tasks cpuset. - in page_alloc, to restrict memory to allowed nodes. diff --git a/Documentation/devices.txt b/Documentation/devices.txt index bb67cf2..0f51517 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -94,6 +94,7 @@ Your cooperation is appreciated. 9 = /dev/urandom Faster, less secure random number gen. 10 = /dev/aio Asyncronous I/O notification interface 11 = /dev/kmsg Writes to this come out as printk's + 12 = /dev/oldmem Access to crash dump from kexec kernel 1 block RAM disk 0 = /dev/ram0 First RAM disk 1 = /dev/ram1 Second RAM disk diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt index d64430b..3a32607 100644 --- a/Documentation/dvb/bt8xx.txt +++ b/Documentation/dvb/bt8xx.txt @@ -44,26 +44,23 @@ TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver. $ modprobe dst The value 0x71 will override the PCI type detection for dvb-bt8xx, -which is necessary for TwinHan cards. +which is necessary for TwinHan cards. If you're having an older card (blue color circuit) and card=0x71 locks your machine, try using 0x68, too. If that does not work, ask on the mailing list. -The DST module takes a couple of useful parameters. +The DST module takes a couple of useful parameters: -verbose takes values 0 to 5. These values control the verbosity level. - -debug takes values 0 and 1. You can either disable or enable debugging. - -dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card. -0x20 means it has a Conditional Access slot. - -The autodected values are determined bythe cards 'response -string' which you can see in your logs e.g. - -dst_get_device_id: Recognise [DSTMCI] +a. verbose takes values 0 to 5. These values control the verbosity level. +b. debug takes values 0 and 1. You can either disable or enable debugging. +c. dst_addons takes values 0 and 0x20: +- A value of 0 means it is a FTA card. +- A value of 0x20 means it has a Conditional Access slot. +The autodetected values are determined by the "response string" +of the card, which you can see in your logs: +e.g.: dst_get_device_id: Recognize [DSTMCI] -- -Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham +Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 77511af..1d227ee 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -43,6 +43,14 @@ Who: Randy Dunlap <rddunlap@osdl.org> --------------------------- +What: RAW driver (CONFIG_RAW_DRIVER) +When: December 2005 +Why: declared obsolete since kernel 2.6.3 + O_DIRECT can be used instead +Who: Adrian Bunk <bunk@stusta.de> + +--------------------------- + What: register_ioctl32_conversion() / unregister_ioctl32_conversion() When: April 2005 Why: Replaced by ->compat_ioctl in file_operations and other method diff --git a/Documentation/kdump/gdbmacros.txt b/Documentation/kdump/gdbmacros.txt new file mode 100644 index 0000000..bc1b9eb --- /dev/null +++ b/Documentation/kdump/gdbmacros.txt @@ -0,0 +1,179 @@ +# +# This file contains a few gdb macros (user defined commands) to extract +# useful information from kernel crashdump (kdump) like stack traces of +# all the processes or a particular process and trapinfo. +# +# These macros can be used by copying this file in .gdbinit (put in home +# directory or current directory) or by invoking gdb command with +# --command=<command-file-name> option +# +# Credits: +# Alexander Nyberg <alexn@telia.com> +# V Srivatsa <vatsa@in.ibm.com> +# Maneesh Soni <maneesh@in.ibm.com> +# + +define bttnobp + set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) + set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) + set $init_t=&init_task + set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) + while ($next_t != $init_t) + set $next_t=(struct task_struct *)$next_t + printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm + printf "===================\n" + set var $stackp = $next_t.thread.esp + set var $stack_top = ($stackp & ~4095) + 4096 + + while ($stackp < $stack_top) + if (*($stackp) > _stext && *($stackp) < _sinittext) + info symbol *($stackp) + end + set $stackp += 4 + end + set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) + while ($next_th != $next_t) + set $next_th=(struct task_struct *)$next_th + printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm + printf "===================\n" + set var $stackp = $next_t.thread.esp + set var $stack_top = ($stackp & ~4095) + 4096 + + while ($stackp < $stack_top) + if (*($stackp) > _stext && *($stackp) < _sinittext) + info symbol *($stackp) + end + set $stackp += 4 + end + set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) + end + set $next_t=(char *)($next_t->tasks.next) - $tasks_off + end +end +document bttnobp + dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER +end + +define btt + set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) + set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) + set $init_t=&init_task + set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) + while ($next_t != $init_t) + set $next_t=(struct task_struct *)$next_t + printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm + printf "===================\n" + set var $stackp = $next_t.thread.esp + set var $stack_top = ($stackp & ~4095) + 4096 + set var $stack_bot = ($stackp & ~4095) + + set $stackp = *($stackp) + while (($stackp < $stack_top) && ($stackp > $stack_bot)) + set var $addr = *($stackp + 4) + info symbol $addr + set $stackp = *($stackp) + end + + set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) + while ($next_th != $next_t) + set $next_th=(struct task_struct *)$next_th + printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm + printf "===================\n" + set var $stackp = $next_t.thread.esp + set var $stack_top = ($stackp & ~4095) + 4096 + set var $stack_bot = ($stackp & ~4095) + + set $stackp = *($stackp) + while (($stackp < $stack_top) && ($stackp > $stack_bot)) + set var $addr = *($stackp + 4) + info symbol $addr + set $stackp = *($stackp) + end + set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) + end + set $next_t=(char *)($next_t->tasks.next) - $tasks_off + end +end +document btt + dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER +end + +define btpid + set var $pid = $arg0 + set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) + set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) + set $init_t=&init_task + set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) + set var $pid_task = 0 + + while ($next_t != $init_t) + set $next_t=(struct task_struct *)$next_t + + if ($next_t.pid == $pid) + set $pid_task = $next_t + end + + set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) + while ($next_th != $next_t) + set $next_th=(struct task_struct *)$next_th + if ($next_th.pid == $pid) + set $pid_task = $next_th + end + set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) + end + set $next_t=(char *)($next_t->tasks.next) - $tasks_off + end + + printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm + printf "===================\n" + set var $stackp = $pid_task.thread.esp + set var $stack_top = ($stackp & ~4095) + 4096 + set var $stack_bot = ($stackp & ~4095) + + set $stackp = *($stackp) + while (($stackp < $stack_top) && ($stackp > $stack_bot)) + set var $addr = *($stackp + 4) + info symbol $addr + set $stackp = *($stackp) + end +end +document btpid + backtrace of pid +end + + +define trapinfo + set var $pid = $arg0 + set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) + set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) + set $init_t=&init_task + set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) + set var $pid_task = 0 + + while ($next_t != $init_t) + set $next_t=(struct task_struct *)$next_t + + if ($next_t.pid == $pid) + set $pid_task = $next_t + end + + set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) + while ($next_th != $next_t) + set $next_th=(struct task_struct *)$next_th + if ($next_th.pid == $pid) + set $pid_task = $next_th + end + set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) + end + set $next_t=(char *)($next_t->tasks.next) - $tasks_off + end + + printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \ + $pid_task.thread.cr2, $pid_task.thread.error_code + +end +document trapinfo + Run info threads and lookup pid of thread #1 + 'trapinfo <pid>' will tell you by which trap & possibly + addresthe kernel paniced. +end diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt new file mode 100644 index 0000000..7ff213f --- /dev/null +++ b/Documentation/kdump/kdump.txt @@ -0,0 +1,141 @@ +Documentation for kdump - the kexec-based crash dumping solution +================================================================ + +DESIGN +====== + +Kdump uses kexec to reboot to a second kernel whenever a dump needs to be taken. +This second kernel is booted with very little memory. The first kernel reserves +the section of memory that the second kernel uses. This ensures that on-going +DMA from the first kernel does not corrupt the second kernel. + +All the necessary information about Core image is encoded in ELF format and +stored in reserved area of memory before crash. Physical address of start of +ELF header is passed to new kernel through command line parameter elfcorehdr=. + +On i386, the first 640 KB of physical memory is needed to boot, irrespective +of where the kernel loads. Hence, this region is backed up by kexec just before +rebooting into the new kernel. + +In the second kernel, "old memory" can be accessed in two ways. + +- The first one is through a /dev/oldmem device interface. A capture utility + can read the device file and write out the memory in raw format. This is raw + dump of memory and analysis/capture tool should be intelligent enough to + determine where to look for the right information. ELF headers (elfcorehdr=) + can become handy here. + +- The second interface is through /proc/vmcore. This exports the dump as an ELF + format file which can be written out using any file copy command + (cp, scp, etc). Further, gdb can be used to perform limited debugging on + the dump file. This method ensures methods ensure that there is correct + ordering of the dump pages (corresponding to the first 640 KB that has been + relocated). + +SETUP +===== + +1) Download http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz + and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch + and after that build the source. + +2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel + patchset and apply it to the vanilla kernel tree. + + Two kernels need to be built in order to get this feature working. + + A) First kernel: + a) Enable "kexec system call" feature (in Processor type and features). + CONFIG_KEXEC=y + b) This kernel's physical load address should be the default value of + 0x100000 (0x100000, 1 MB) (in Processor type and features). + CONFIG_PHYSICAL_START=0x100000 + c) Enable "sysfs file system support" (in Pseudo filesystems). + CONFIG_SYSFS=y + d) Boot into first kernel with the command line parameter "crashkernel=Y@X". + Use appropriate values for X and Y. Y denotes how much memory to reserve + for the second kernel, and X denotes at what physical address the reserved + memory section starts. For example: "crashkernel=64M@16M". + + B) Second kernel: + a) Enable "kernel crash dumps" feature (in Processor type and features). + CONFIG_CRASH_DUMP=y + b) Specify a suitable value for "Physical address where the kernel is + loaded" (in Processor type and features). Typically this value + should be same as X (See option d) above, e.g., 16 MB or 0x1000000. + CONFIG_PHYSICAL_START=0x1000000 + c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems). + CONFIG_PROC_VMCORE=y + d) Disable SMP support and build a UP kernel (Until it is fixed). + CONFIG_SMP=n + e) Enable "Local APIC support on uniprocessors". + CONFIG_X86_UP_APIC=y + f) Enable "IO-APIC support on uniprocessors" + CONFIG_X86_UP_IOAPIC=y + + Note: i) Options a) and b) depend upon "Configure standard kernel features + (for small systems)" (under General setup). + ii) Option a) also depends on CONFIG_HIGHMEM (under Processor + type and features). + iii) Both option a) and b) are under "Processor type and features". + +3) Boot into the first kernel. You are now ready to try out kexec-based crash + dumps. + +4) Load the second kernel to be booted using: + + kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev> + init 1 irqpoll" + + Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work, + as of now. + ii) By default ELF headers are stored in ELF32 format (for i386). This + is sufficient to represent the physical memory up to 4GB. To store + headers in ELF64 format, specifiy "--elf64-core-headers" on the + kexec command line additionally. + iii) Specify "irqpoll" as command line parameter. This reduces driver + initialization failures in second kernel due to shared interrupts. + +5) System reboots into the second kernel when a panic occurs. A module can be + written to force the panic or "ALT-SysRq-c" can be used initiate a crash + dump for testing purposes. + +6) Write out the dump file using + + cp /proc/vmcore <dump-file> + + Dump memory can also be accessed as a /dev/oldmem device for a linear/raw + view. To create the device, type: + + mknod /dev/oldmem c 1 12 + + Use "dd" with suitable options for count, bs and skip to access specific + portions of the dump. + + Entire memory: dd if=/dev/oldmem of=oldmem.001 + +ANALYSIS +======== + +Limited analysis can be done using gdb on the dump file copied out of +/proc/vmcore. Use vmlinux built with -g and run + + gdb vmlinux <dump-file> + +Stack trace for the task on processor 0, register display, memory display +work fine. + +Note: gdb cannot analyse core files generated in ELF64 format for i386. + +TODO +==== + +1) Provide a kernel pages filtering mechanism so that core file size is not + insane on systems having huge memory banks. +2) Modify "crash" tool to make it recognize this dump. + +CONTACT +======= + +Vivek Goyal (vgoyal@in.ibm.com) +Maneesh Soni (maneesh@in.ibm.com) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 4924d387..f44bb55 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -358,6 +358,10 @@ running once the system is up. cpia_pp= [HW,PPT] Format: { parport<nr> | auto | none } + crashkernel=nn[KMG]@ss[KMG] + [KNL] Reserve a chunk of physical memory to + hold a kernel to switch to with kexec on panic. + cs4232= [HW,OSS] Format: <io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq> @@ -447,6 +451,10 @@ running once the system is up. Format: {"as"|"cfq"|"deadline"|"noop"} See Documentation/block/as-iosched.txt and Documentation/block/deadline-iosched.txt for details. + elfcorehdr= [IA-32] + Specifies physical address of start of kernel core image + elf header. + See Documentation/kdump.txt for details. enforcing [SELINUX] Set initial enforcing status. Format: {"0" | "1"} @@ -548,6 +556,9 @@ running once the system is up. i810= [HW,DRM] + i8k.ignore_dmi [HW] Continue probing hardware even if DMI data + indicates that the driver is running on unsupported + hardware. i8k.force [HW] Activate i8k driver even if SMM BIOS signature does not match list of supported models. i8k.power_status diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 834993d..5b01d5c 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -114,9 +114,7 @@ tuntap.txt vortex.txt - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. wan-router.txt - - Wan router documentation -wanpipe.txt - - WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router + - WAN router documentation wavelan.txt - AT&T GIS (nee NCR) WaveLAN card: An Ethernet-like radio transceiver x25.txt diff --git a/Documentation/networking/wanpipe.txt b/Documentation/networking/wanpipe.txt deleted file mode 100644 index aea20cd..0000000 --- a/Documentation/networking/wanpipe.txt +++ /dev/null @@ -1,622 +0,0 @@ ------------------------------------------------------------------------------- -Linux WAN Router Utilities Package ------------------------------------------------------------------------------- -Version 2.2.1 -Mar 28, 2001 -Author: Nenad Corbic <ncorbic@sangoma.com> -Copyright (c) 1995-2001 Sangoma Technologies Inc. ------------------------------------------------------------------------------- - -INTRODUCTION - -Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs) -and/or stand-alone hosts over vast distances with data transfer rates -significantly higher than those achievable with commonly used dial-up -connections. - -Usually an external device called `WAN router' sitting on your local network -or connected to your machine's serial port provides physical connection to -WAN. Although router's job may be as simple as taking your local network -traffic, converting it to WAN format and piping it through the WAN link, these -devices are notoriously expensive, with prices as much as 2 - 5 times higher -then the price of a typical PC box. - -Alternatively, considering robustness and multitasking capabilities of Linux, -an internal router can be built (most routers use some sort of stripped down -Unix-like operating system anyway). With a number of relatively inexpensive WAN -interface cards available on the market, a perfectly usable router can be -built for less than half a price of an external router. Yet a Linux box -acting as a router can still be used for other purposes, such as fire-walling, -running FTP, WWW or DNS server, etc. - -This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux -operating system and provides generic hardware-independent services for such -drivers. Why can existing Linux network device interface not be used for -this purpose? Well, it can. However, there are a few key differences between -a typical network interface (e.g. Ethernet) and a WAN link. - -Many WAN protocols, such as X.25 and frame relay, allow for multiple logical -connections (known as `virtual circuits' in X.25 terminology) over a single -physical link. Each such virtual circuit may (and almost always does) lead -to a different geographical location and, therefore, different network. As a -result, it is the virtual circuit, not the physical link, that represents a -route and, therefore, a network interface in Linux terms. - -To further complicate things, virtual circuits are usually volatile in nature -(excluding so called `permanent' virtual circuits or PVCs). With almost no -time required to set up and tear down a virtual circuit, it is highly desirable -to implement on-demand connections in order to minimize network charges. So -unlike a typical network driver, the WAN driver must be able to handle multiple -network interfaces and cope as multiple virtual circuits come into existence -and go away dynamically. - -Last, but not least, WAN configuration is much more complex than that of say -Ethernet and may well amount to several dozens of parameters. Some of them -are "link-wide" while others are virtual circuit-specific. The same holds -true for WAN statistics which is by far more extensive and extremely useful -when troubleshooting WAN connections. Extending the ifconfig utility to suit -these needs may be possible, but does not seem quite reasonable. Therefore, a -WAN configuration utility and corresponding application programmer's interface -is needed for this purpose. - -Most of these problems are taken care of by this module. Its goal is to -provide a user with more-or-less standard look and feel for all WAN devices and -assist a WAN device driver writer by providing common services, such as: - - o User-level interface via /proc file system - o Centralized configuration - o Device management (setup, shutdown, etc.) - o Network interface management (dynamic creation/destruction) - o Protocol encapsulation/decapsulation - -To ba able to use the Linux WAN Router you will also need a WAN Tools package -available from - - ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz - -where vX.Y.Z represent the wanpipe version number. - -For technical questions and/or comments please e-mail to ncorbic@sangoma.com. -For general inquiries please contact Sangoma Technologies Inc. by - - Hotline: 1-800-388-2475 (USA and Canada, toll free) - Phone: (905) 474-1990 ext: 106 - Fax: (905) 474-9223 - E-mail: dm@sangoma.com (David Mandelstam) - WWW: http://www.sangoma.com - - -INSTALLATION - -Please read the WanpipeForLinux.pdf manual on how to -install the WANPIPE tools and drivers properly. - - -After installing wanpipe package: /usr/local/wanrouter/doc. -On the ftp.sangoma.com : /linux/current_wanpipe/doc - - -COPYRIGHT AND LICENSING INFORMATION - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; either version 2, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 675 Mass -Ave, Cambridge, MA 02139, USA. - - - -ACKNOWLEDGEMENTS - -This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed -by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE -together with the next major release of Linux kernel in summer 1996 commanded -adequate changes to the WANPIPE code to take full advantage of new Linux -features. - -Instead of continuing developing proprietary interface tied to Sangoma WAN -cards, we decided to separate all hardware-independent code into a separate -module and defined two levels of interfaces - one for user-level applications -and another for kernel-level WAN drivers. WANPIPE is now implemented as a -WAN driver compliant with the WAN Link Driver interface. Also a general -purpose WAN configuration utility and a set of shell scripts was developed to -support WAN router at the user level. - -Many useful ideas concerning hardware-independent interface implementation -were given by Mike McLagan <mike.mclagan@linux.org> and his implementation -of the Frame Relay router and drivers for Sangoma cards (dlci/sdla). - -With the new implementation of the APIs being incorporated into the WANPIPE, -a special thank goes to Alan Cox in providing insight into BSD sockets. - -Special thanks to all the WANPIPE users who performed field-testing, reported -bugs and made valuable comments and suggestions that help us to improve this -product. - - - -NEW IN THIS RELEASE - - o Updated the WANCFG utility - Calls the pppconfig to configure the PPPD - for async connections. - - o Added the PPPCONFIG utility - Used to configure the PPPD dameon for the - WANPIPE Async PPP and standard serial port. - The wancfg calls the pppconfig to configure - the pppd. - - o Fixed the PCI autodetect feature. - The SLOT 0 was used as an autodetect option - however, some high end PC's slot numbers start - from 0. - - o This release has been tested with the new backupd - daemon release. - - -PRODUCT COMPONENTS AND RELATED FILES - -/etc: (or user defined) - wanpipe1.conf default router configuration file - -/lib/modules/X.Y.Z/misc: - wanrouter.o router kernel loadable module - af_wanpipe.o wanpipe api socket module - -/lib/modules/X.Y.Z/net: - sdladrv.o Sangoma SDLA support module - wanpipe.o Sangoma WANPIPE(tm) driver module - -/proc/net/wanrouter - Config reads current router configuration - Status reads current router status - {name} reads WAN driver statistics - -/usr/sbin: - wanrouter wanrouter start-up script - wanconfig wanrouter configuration utility - sdladump WANPIPE adapter memory dump utility - fpipemon Monitor for Frame Relay - cpipemon Monitor for Cisco HDLC - ppipemon Monitor for PPP - xpipemon Monitor for X25 - wpkbdmon WANPIPE keyboard led monitor/debugger - -/usr/local/wanrouter: - README this file - COPYING GNU General Public License - Setup installation script - Filelist distribution definition file - wanrouter.rc meta-configuration file - (used by the Setup and wanrouter script) - -/usr/local/wanrouter/doc: - wanpipeForLinux.pdf WAN Router User's Manual - -/usr/local/wanrouter/patches: - wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13. - wanrouter-v2214.gz patch for Linux kernel 2.2.14. - wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17. - wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up. - wanrouter-v240.gz patch for Linux kernel 2.4.0. - wanrouter-v242.gz patch for Linux kernel 2.4.2 and up. - wanrouter-v2034.gz patch for Linux kernel 2.0.34 - wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up. - -/usr/local/wanrouter/patches/kdrivers: - Sources of the latest WANPIPE device drivers. - These are used to UPGRADE the linux kernel to the newest - version if the kernel source has already been pathced with - WANPIPE drivers. - -/usr/local/wanrouter/samples: - interface sample interface configuration file - wanpipe1.cpri CHDLC primary port - wanpipe2.csec CHDLC secondary port - wanpipe1.fr Frame Relay protocol - wanpipe1.ppp PPP protocol ) - wanpipe1.asy CHDLC ASYNC protocol - wanpipe1.x25 X25 protocol - wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon) - wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon) - wanrouter.rc sample meta-configuration file - -/usr/local/wanrouter/util: - * wan-tools utilities source code - -/usr/local/wanrouter/api/x25: - * x25 api sample programs. -/usr/local/wanrouter/api/chdlc: - * chdlc api sample programs. -/usr/local/wanrouter/api/fr: - * fr api sample programs. -/usr/local/wanrouter/config/wancfg: - wancfg WANPIPE GUI configuration program. - Creates wanpipe#.conf files. -/usr/local/wanrouter/config/cfgft1: - cfgft1 GUI CSU/DSU configuration program. - -/usr/include/linux: - wanrouter.h router API definitions - wanpipe.h WANPIPE API definitions - sdladrv.h SDLA support module API definitions - sdlasfm.h SDLA firmware module definitions - if_wanpipe.h WANPIPE Socket definitions - if_wanpipe_common.h WANPIPE Socket/Driver common definitions. - sdlapci.h WANPIPE PCI definitions - - -/usr/src/linux/net/wanrouter: - * wanrouter source code - -/var/log: - wanrouter wanrouter start-up log (created by the Setup script) - -/var/lock: (or /var/lock/subsys for RedHat) - wanrouter wanrouter lock file (created by the Setup script) - -/usr/local/wanrouter/firmware: - fr514.sfm Frame relay firmware for Sangoma S508/S514 card - cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card - ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards - x25_508.sfm X25 Firmware for Sangoma S508 card. - - -REVISION HISTORY - -1.0.0 December 31, 1996 Initial version - -1.0.1 January 30, 1997 Status and statistics can be read via /proc - filesystem entries. - -1.0.2 April 30, 1997 Added UDP management via monitors. - -1.0.3 June 3, 1997 UDP management for multiple boards using Frame - Relay and PPP - Enabled continuous transmission of Configure - Request Packet for PPP (for 508 only) - Connection Timeout for PPP changed from 900 to 0 - Flow Control Problem fixed for Frame Relay - -1.0.4 July 10, 1997 S508/FT1 monitoring capability in fpipemon and - ppipemon utilities. - Configurable TTL for UDP packets. - Multicast and Broadcast IP source addresses are - silently discarded. - -1.0.5 July 28, 1997 Configurable T391,T392,N391,N392,N393 for Frame - Relay in router.conf. - Configurable Memory Address through router.conf - for Frame Relay, PPP and X.25. (commenting this - out enables auto-detection). - Fixed freeing up received buffers using kfree() - for Frame Relay and X.25. - Protect sdla_peek() by calling save_flags(), - cli() and restore_flags(). - Changed number of Trace elements from 32 to 20 - Added DLCI specific data monitoring in FPIPEMON. -2.0.0 Nov 07, 1997 Implemented protection of RACE conditions by - critical flags for FRAME RELAY and PPP. - DLCI List interrupt mode implemented. - IPX support in FRAME RELAY and PPP. - IPX Server Support (MARS) - More driver specific stats included in FPIPEMON - and PIPEMON. - -2.0.1 Nov 28, 1997 Bug Fixes for version 2.0.0. - Protection of "enable_irq()" while - "disable_irq()" has been enabled from any other - routine (for Frame Relay, PPP and X25). - Added additional Stats for Fpipemon and Ppipemon - Improved Load Sharing for multiple boards - -2.0.2 Dec 09, 1997 Support for PAP and CHAP for ppp has been - implemented. - -2.0.3 Aug 15, 1998 New release supporting Cisco HDLC, CIR for Frame - relay, Dynamic IP assignment for PPP and Inverse - Arp support for Frame-relay. Man Pages are - included for better support and a new utility - for configuring FT1 cards. - -2.0.4 Dec 09, 1998 Dual Port support for Cisco HDLC. - Support for HDLC (LAPB) API. - Supports BiSync Streaming code for S502E - and S503 cards. - Support for Streaming HDLC API. - Provides a BSD socket interface for - creating applications using BiSync - streaming. - -2.0.5 Aug 04, 1999 CHDLC initializatin bug fix. - PPP interrupt driven driver: - Fix to the PPP line hangup problem. - New PPP firmware - Added comments to the startup SYSTEM ERROR messages - Xpipemon debugging application for the X25 protocol - New USER_MANUAL.txt - Fixed the odd boundary 4byte writes to the board. - BiSync Streaming code has been taken out. - Available as a patch. - Streaming HDLC API has been taken out. - Available as a patch. - -2.0.6 Aug 17, 1999 Increased debugging in statup scripts - Fixed insallation bugs from 2.0.5 - Kernel patch works for both 2.2.10 and 2.2.11 kernels. - There is no functional difference between the two packages - -2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. - o Fixed a memeory leak for X25API - o Updated the X25API code for 2.2.X kernels. - o Improved NEM handling. - -2.1.0 Oct 25, 1999 o New code for S514 PCI Card - o New CHDLC and Frame Relay drivers - o PPP and X25 are not supported in this release - -2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards - -2.1.3 Apr 06, 2000 o Socket based x25api - o Socket based chdlc api - o Socket based fr api - o Dual Port Receive only CHDLC support. - o Asynchronous CHDLC support (Secondary Port) - o cfgft1 GUI csu/dsu configurator - o wancfg GUI configuration file - configurator. - o Architectual directory changes. - -beta-2.1.4 Jul 2000 o Dynamic interface configuration: - Network interfaces reflect the state - of protocol layer. If the protocol becomes - disconnected, driver will bring down - the interface. Once the protocol reconnects - the interface will be brought up. - - Note: This option is turned off by default. - - o Dynamic wanrouter setup using 'wanconfig': - wanconfig utility can be used to - shutdown,restart,start or reconfigure - a virtual circuit dynamically. - - Frame Relay: Each DLCI can be: - created,stopped,restarted and reconfigured - dynamically using wanconfig. - - ex: wanconfig card wanpipe1 dev wp1_fr16 up - - o Wanrouter startup via command line arguments: - wanconfig also supports wanrouter startup via command line - arguments. Thus, there is no need to create a wanpipe#.conf - configuration file. - - o Socket based x25api update/bug fixes. - Added support for LCN numbers greater than 255. - Option to pass up modem messages. - Provided a PCI IRQ check, so a single S514 - card is guaranteed to have a non-sharing interrupt. - - o Fixes to the wancfg utility. - o New FT1 debugging support via *pipemon utilities. - o Frame Relay ARP support Enabled. - -beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix. - o Added the Multi-Port PPP - Updated utilites for the Multi-Port PPP. - -2.1.4 Aut 2000 - o In X25API: - Maximum packet an application can send - to the driver has been extended to 4096 bytes. - - Fixed the x25 startup bug. Enable - communications only after all interfaces - come up. HIGH SVC/PVC is used to calculate - the number of channels. - Enable protocol only after all interfaces - are enabled. - - o Added an extra state to the FT1 config, kernel module. - o Updated the pipemon debuggers. - - o Blocked the Multi-Port PPP from running on kernels - 2.2.16 or greater, due to syncppp kernel module - change. - -beta1-2.1.5 Nov 15 2000 - o Fixed the MulitPort PPP Support for kernels 2.2.16 and above. - 2.2.X kernels only - - o Secured the driver UDP debugging calls - - All illegal netowrk debugging calls are reported to - the log. - - Defined a set of allowed commands, all other denied. - - o Cpipemon - - Added set FT1 commands to the cpipemon. Thus CSU/DSU - configuraiton can be performed using cpipemon. - All systems that cannot run cfgft1 GUI utility should - use cpipemon to configure the on board CSU/DSU. - - - o Keyboard Led Monitor/Debugger - - A new utilty /usr/sbin/wpkbdmon uses keyboard leds - to convey operatinal statistic information of the - Sangoma WANPIPE cards. - NUM_LOCK = Line State (On=connected, Off=disconnected) - CAPS_LOCK = Tx data (On=transmitting, Off=no tx data) - SCROLL_LOCK = Rx data (On=receiving, Off=no rx data - - o Hardware probe on module load and dynamic device allocation - - During WANPIPE module load, all Sangoma cards are probed - and found information is printed in the /var/log/messages. - - If no cards are found, the module load fails. - - Appropriate number of devices are dynamically loaded - based on the number of Sangoma cards found. - - Note: The kernel configuraiton option - CONFIG_WANPIPE_CARDS has been taken out. - - o Fixed the Frame Relay and Chdlc network interfaces so they are - compatible with libpcap libraries. Meaning, tcpdump, snort, - ethereal, and all other packet sniffers and debuggers work on - all WANPIPE netowrk interfaces. - - Set the network interface encoding type to ARPHRD_PPP. - This tell the sniffers that data obtained from the - network interface is in pure IP format. - Fix for 2.2.X kernels only. - - o True interface encoding option for Frame Relay and CHDLC - - The above fix sets the network interface encoding - type to ARPHRD_PPP, however some customers use - the encoding interface type to determine the - protocol running. Therefore, the TURE ENCODING - option will set the interface type back to the - original value. - - NOTE: If this option is used with Frame Relay and CHDLC - libpcap library support will be broken. - i.e. tcpdump will not work. - Fix for 2.2.x Kernels only. - - o Ethernet Bridgind over Frame Relay - - The Frame Relay bridging has been developed by - Kristian Hoffmann and Mark Wells. - - The Linux kernel bridge is used to send ethernet - data over the frame relay links. - For 2.2.X Kernels only. - - o Added extensive 2.0.X support. Most new features of - 2.1.5 for protocols Frame Relay, PPP and CHDLC are - supported under 2.0.X kernels. - -beta1-2.2.0 Dec 30 2000 - o Updated drivers for 2.4.X kernels. - o Updated drivers for SMP support. - o X25API is now able to share PCI interrupts. - o Took out a general polling routine that was used - only by X25API. - o Added appropriate locks to the dynamic reconfiguration - code. - o Fixed a bug in the keyboard debug monitor. - -beta2-2.2.0 Jan 8 2001 - o Patches for 2.4.0 kernel - o Patches for 2.2.18 kernel - o Minor updates to PPP and CHLDC drivers. - Note: No functinal difference. - -beta3-2.2.9 Jan 10 2001 - o I missed the 2.2.18 kernel patches in beta2-2.2.0 - release. They are included in this release. - -Stable Release -2.2.0 Feb 01 2001 - o Bug fix in wancfg GUI configurator. - The edit function didn't work properly. - - -bata1-2.2.1 Feb 09 2001 - o WANPIPE TTY Driver emulation. - Two modes of operation Sync and Async. - Sync: Using the PPPD daemon, kernel SyncPPP layer - and the Wanpipe sync TTY driver: a PPP protocol - connection can be established via Sangoma adapter, over - a T1 leased line. - - The 2.4.0 kernel PPP layer supports MULTILINK - protocol, that can be used to bundle any number of Sangoma - adapters (T1 lines) into one, under a single IP address. - Thus, efficiently obtaining multiple T1 throughput. - - NOTE: The remote side must also implement MULTILINK PPP - protocol. - - Async:Using the PPPD daemon, kernel AsyncPPP layer - and the WANPIPE async TTY driver: a PPP protocol - connection can be established via Sangoma adapter and - a modem, over a telephone line. - - Thus, the WANPIPE async TTY driver simulates a serial - TTY driver that would normally be used to interface the - MODEM to the linux kernel. - - o WANPIPE PPP Backup Utility - This utility will monitor the state of the PPP T1 line. - In case of failure, a dial up connection will be established - via pppd daemon, ether via a serial tty driver (serial port), - or a WANPIPE async TTY driver (in case serial port is unavailable). - - Furthermore, while in dial up mode, the primary PPP T1 link - will be monitored for signs of life. - - If the PPP T1 link comes back to life, the dial up connection - will be shutdown and T1 line re-established. - - - o New Setup installation script. - Option to UPGRADE device drivers if the kernel source has - already been patched with WANPIPE. - - Option to COMPILE WANPIPE modules against the currently - running kernel, thus no need for manual kernel and module - re-compilatin. - - o Updates and Bug Fixes to wancfg utility. - -bata2-2.2.1 Feb 20 2001 - - o Bug fixes to the CHDLC device drivers. - The driver had compilation problems under kernels - 2.2.14 or lower. - - o Bug fixes to the Setup installation script. - The device drivers compilation options didn't work - properly. - - o Update to the wpbackupd daemon. - Optimized the cross-over times, between the primary - link and the backup dialup. - -beta3-2.2.1 Mar 02 2001 - o Patches for 2.4.2 kernel. - - o Bug fixes to util/ make files. - o Bug fixes to the Setup installation script. - - o Took out the backupd support and made it into - as separate package. - -beta4-2.2.1 Mar 12 2001 - - o Fix to the Frame Relay Device driver. - IPSAC sends a packet of zero length - header to the frame relay driver. The - driver tries to push its own 2 byte header - into the packet, which causes the driver to - crash. - - o Fix the WANPIPE re-configuration code. - Bug was found by trying to run the cfgft1 while the - interface was already running. - - o Updates to cfgft1. - Writes a wanpipe#.cfgft1 configuration file - once the CSU/DSU is configured. This file can - holds the current CSU/DSU configuration. - - - ->>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - diff --git a/Documentation/power/kernel_threads.txt b/Documentation/power/kernel_threads.txt index 60b5481..fb57784 100644 --- a/Documentation/power/kernel_threads.txt +++ b/Documentation/power/kernel_threads.txt @@ -12,8 +12,7 @@ refrigerator. Code to do this looks like this: do { hub_events(); wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); from drivers/usb/core/hub.c::hub_thread() diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt index 35b1a7d..6fc9d51 100644 --- a/Documentation/power/pci.txt +++ b/Documentation/power/pci.txt @@ -291,6 +291,44 @@ a request to enable wake events from D3, two calls should be made to pci_enable_wake (one for both D3hot and D3cold). +A reference implementation +------------------------- +.suspend() +{ + /* driver specific operations */ + + /* Disable IRQ */ + free_irq(); + /* If using MSI */ + pci_disable_msi(); + + pci_save_state(); + pci_enable_wake(); + /* Disable IO/bus master/irq router */ + pci_disable_device(); + pci_set_power_state(pci_choose_state()); +} + +.resume() +{ + pci_set_power_state(PCI_D0); + pci_restore_state(); + /* device's irq possibly is changed, driver should take care */ + pci_enable_device(); + pci_set_master(); + + /* if using MSI, device's vector possibly is changed */ + pci_enable_msi(); + + request_irq(); + /* driver specific operations; */ +} + +This is a typical implementation. Drivers can slightly change the order +of the operations in the implementation, ignore some operations or add +more deriver specific operations in it, but drivers should do something like +this on the whole. + 5. Resources ~~~~~~~~~~~~ diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index c7c3459..7a6b789 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt @@ -164,11 +164,11 @@ place where the thread is safe to be frozen (no kernel semaphores should be held at that point and it must be safe to sleep there), and add: - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); If the thread is needed for writing the image to storage, you should -instead set the PF_NOFREEZE process flag when creating the thread. +instead set the PF_NOFREEZE process flag when creating the thread (and +be very carefull). Q: What is the difference between between "platform", "shutdown" and @@ -233,3 +233,81 @@ A: Try running cat `cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u` > /dev/null after resume. swapoff -a; swapon -a may also be usefull. + +Q: What happens to devices during swsusp? They seem to be resumed +during system suspend? + +A: That's correct. We need to resume them if we want to write image to +disk. Whole sequence goes like + + Suspend part + ~~~~~~~~~~~~ + running system, user asks for suspend-to-disk + + user processes are stopped + + suspend(PMSG_FREEZE): devices are frozen so that they don't interfere + with state snapshot + + state snapshot: copy of whole used memory is taken with interrupts disabled + + resume(): devices are woken up so that we can write image to swap + + write image to swap + + suspend(PMSG_SUSPEND): suspend devices so that we can power off + + turn the power off + + Resume part + ~~~~~~~~~~~ + (is actually pretty similar) + + running system, user asks for suspend-to-disk + + user processes are stopped (in common case there are none, but with resume-from-initrd, noone knows) + + read image from disk + + suspend(PMSG_FREEZE): devices are frozen so that they don't interfere + with image restoration + + image restoration: rewrite memory with image + + resume(): devices are woken up so that system can continue + + thaw all user processes + +Q: What is this 'Encrypt suspend image' for? + +A: First of all: it is not a replacement for dm-crypt encrypted swap. +It cannot protect your computer while it is suspended. Instead it does +protect from leaking sensitive data after resume from suspend. + +Think of the following: you suspend while an application is running +that keeps sensitive data in memory. The application itself prevents +the data from being swapped out. Suspend, however, must write these +data to swap to be able to resume later on. Without suspend encryption +your sensitive data are then stored in plaintext on disk. This means +that after resume your sensitive data are accessible to all +applications having direct access to the swap device which was used +for suspend. If you don't need swap after resume these data can remain +on disk virtually forever. Thus it can happen that your system gets +broken in weeks later and sensitive data which you thought were +encrypted and protected are retrieved and stolen from the swap device. +To prevent this situation you should use 'Encrypt suspend image'. + +During suspend a temporary key is created and this key is used to +encrypt the data written to disk. When, during resume, the data was +read back into memory the temporary key is destroyed which simply +means that all data written to disk during suspend are then +inaccessible so they can't be stolen later on. The only thing that +you must then take care of is that you call 'mkswap' for the swap +partition used for suspend as early as possible during regular +boot. This asserts that any temporary key from an oopsed suspend or +from a failed or aborted resume is erased from the swap device. + +As a rule of thumb use encrypted swap to protect your data while your +system is shut down or suspended. Additionally use the encrypted +suspend image to prevent sensitive data from being stolen after +resume. diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt index 6873435..881a37e 100644 --- a/Documentation/power/video.txt +++ b/Documentation/power/video.txt @@ -83,8 +83,10 @@ Compaq Armada E500 - P3-700 none (1) (S1 also works OK) Compaq Evo N620c vga=normal, s3_bios (2) Dell 600m, ATI R250 Lf none (1), but needs xorg-x11-6.8.1.902-1 Dell D600, ATI RV250 vga=normal and X, or try vbestate (6) +Dell D610 vga=normal and X (possibly vbestate (6) too, but not tested) Dell Inspiron 4000 ??? (*) Dell Inspiron 500m ??? (*) +Dell Inspiron 510m ??? Dell Inspiron 600m ??? (*) Dell Inspiron 8200 ??? (*) Dell Inspiron 8500 ??? (*) @@ -123,6 +125,7 @@ Toshiba Satellite 4030CDT s3_mode (3) Toshiba Satellite 4080XCDT s3_mode (3) Toshiba Satellite 4090XCDT ??? (*) Toshiba Satellite P10-554 s3_bios,s3_mode (4)(****) +Toshiba M30 (2) xor X with nvidia driver using internal AGP Uniwill 244IIO ??? (*) diff --git a/Documentation/power/video_extension.txt b/Documentation/power/video_extension.txt index 8e33d7c8..b2f9b15 100644 --- a/Documentation/power/video_extension.txt +++ b/Documentation/power/video_extension.txt @@ -1,13 +1,16 @@ -This driver implement the ACPI Extensions For Display Adapters -for integrated graphics devices on motherboard, as specified in -ACPI 2.0 Specification, Appendix B, allowing to perform some basic -control like defining the video POST device, retrieving EDID information -or to setup a video output, etc. Note that this is an ref. implementation only. -It may or may not work for your integrated video device. +ACPI video extensions +~~~~~~~~~~~~~~~~~~~~~ + +This driver implement the ACPI Extensions For Display Adapters for +integrated graphics devices on motherboard, as specified in ACPI 2.0 +Specification, Appendix B, allowing to perform some basic control like +defining the video POST device, retrieving EDID information or to +setup a video output, etc. Note that this is an ref. implementation +only. It may or may not work for your integrated video device. Interfaces exposed to userland through /proc/acpi/video: -VGA/info : display the supported video bus device capability like ,Video ROM, CRT/LCD/TV. +VGA/info : display the supported video bus device capability like Video ROM, CRT/LCD/TV. VGA/ROM : Used to get a copy of the display devices' ROM data (up to 4k). VGA/POST_info : Used to determine what options are implemented. VGA/POST : Used to get/set POST device. @@ -15,7 +18,7 @@ VGA/DOS : Used to get/set ownership of output switching: Please refer ACPI spec B.4.1 _DOS VGA/CRT : CRT output VGA/LCD : LCD output -VGA/TV : TV output +VGA/TVO : TV output VGA/*/brightness : Used to get/set brightness of output device Notify event through /proc/acpi/event: diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index 2d1cd93..e24fdea 100644 --- a/Documentation/s390/s390dbf.txt +++ b/Documentation/s390/s390dbf.txt @@ -12,8 +12,8 @@ where log records can be stored efficiently in memory, where each component One purpose of this is to inspect the debug logs after a production system crash in order to analyze the reason for the crash. If the system still runs but only a subcomponent which uses dbf failes, -it is possible to look at the debug logs on a live system via the Linux proc -filesystem. +it is possible to look at the debug logs on a live system via the Linux +debugfs filesystem. The debug feature may also very useful for kernel and driver development. Design: @@ -52,16 +52,18 @@ Each debug entry contains the following data: - Flag, if entry is an exception or not The debug logs can be inspected in a live system through entries in -the proc-filesystem. Under the path /proc/s390dbf there is +the debugfs-filesystem. Under the toplevel directory "s390dbf" there is a directory for each registered component, which is named like the -corresponding component. +corresponding component. The debugfs normally should be mounted to +/sys/kernel/debug therefore the debug feature can be accessed unter +/sys/kernel/debug/s390dbf. The content of the directories are files which represent different views to the debug log. Each component can decide which views should be used through registering them with the function debug_register_view(). Predefined views for hex/ascii, sprintf and raw binary data are provided. It is also possible to define other views. The content of -a view can be inspected simply by reading the corresponding proc file. +a view can be inspected simply by reading the corresponding debugfs file. All debug logs have an an actual debug level (range from 0 to 6). The default level is 3. Event and Exception functions have a 'level' @@ -69,14 +71,14 @@ parameter. Only debug entries with a level that is lower or equal than the actual level are written to the log. This means, when writing events, high priority log entries should have a low level value whereas low priority entries should have a high one. -The actual debug level can be changed with the help of the proc-filesystem -through writing a number string "x" to the 'level' proc file which is +The actual debug level can be changed with the help of the debugfs-filesystem +through writing a number string "x" to the 'level' debugfs file which is provided for every debug log. Debugging can be switched off completely -by using "-" on the 'level' proc file. +by using "-" on the 'level' debugfs file. Example: -> echo "-" > /proc/s390dbf/dasd/level +> echo "-" > /sys/kernel/debug/s390dbf/dasd/level It is also possible to deactivate the debug feature globally for every debug log. You can change the behavior using 2 sysctl parameters in @@ -99,11 +101,11 @@ Kernel Interfaces: ------------------ ---------------------------------------------------------------------------- -debug_info_t *debug_register(char *name, int pages_index, int nr_areas, +debug_info_t *debug_register(char *name, int pages, int nr_areas, int buf_size); -Parameter: name: Name of debug log (e.g. used for proc entry) - pages_index: 2^pages_index pages will be allocated per area +Parameter: name: Name of debug log (e.g. used for debugfs entry) + pages: number of pages, which will be allocated per area nr_areas: number of debug areas buf_size: size of data area in each debug entry @@ -134,7 +136,7 @@ Return Value: none Description: Sets new actual debug level if new_level is valid. --------------------------------------------------------------------------- -+void debug_stop_all(void); +void debug_stop_all(void); Parameter: none @@ -270,7 +272,7 @@ Parameter: id: handle for debug log Return Value: 0 : ok < 0: Error -Description: registers new debug view and creates proc dir entry +Description: registers new debug view and creates debugfs dir entry --------------------------------------------------------------------------- int debug_unregister_view (debug_info_t * id, struct debug_view *view); @@ -281,7 +283,7 @@ Parameter: id: handle for debug log Return Value: 0 : ok < 0: Error -Description: unregisters debug view and removes proc dir entry +Description: unregisters debug view and removes debugfs dir entry @@ -308,7 +310,7 @@ static int init(void) { /* register 4 debug areas with one page each and 4 byte data field */ - debug_info = debug_register ("test", 0, 4, 4 ); + debug_info = debug_register ("test", 1, 4, 4 ); debug_register_view(debug_info,&debug_hex_ascii_view); debug_register_view(debug_info,&debug_raw_view); @@ -343,7 +345,7 @@ static int init(void) /* register 4 debug areas with one page each and data field for */ /* format string pointer + 2 varargs (= 3 * sizeof(long)) */ - debug_info = debug_register ("test", 0, 4, sizeof(long) * 3); + debug_info = debug_register ("test", 1, 4, sizeof(long) * 3); debug_register_view(debug_info,&debug_sprintf_view); debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__); @@ -362,16 +364,16 @@ module_exit(cleanup); -ProcFS Interface +Debugfs Interface ---------------- Views to the debug logs can be investigated through reading the corresponding -proc-files: +debugfs-files: Example: -> ls /proc/s390dbf/dasd -flush hex_ascii level raw -> cat /proc/s390dbf/dasd/hex_ascii | sort +1 +> ls /sys/kernel/debug/s390dbf/dasd +flush hex_ascii level pages raw +> cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort +1 00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | .... 00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE 00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | .... @@ -391,25 +393,36 @@ Changing the debug level Example: -> cat /proc/s390dbf/dasd/level +> cat /sys/kernel/debug/s390dbf/dasd/level 3 -> echo "5" > /proc/s390dbf/dasd/level -> cat /proc/s390dbf/dasd/level +> echo "5" > /sys/kernel/debug/s390dbf/dasd/level +> cat /sys/kernel/debug/s390dbf/dasd/level 5 Flushing debug areas -------------------- Debug areas can be flushed with piping the number of the desired -area (0...n) to the proc file "flush". When using "-" all debug areas +area (0...n) to the debugfs file "flush". When using "-" all debug areas are flushed. Examples: 1. Flush debug area 0: -> echo "0" > /proc/s390dbf/dasd/flush +> echo "0" > /sys/kernel/debug/s390dbf/dasd/flush 2. Flush all debug areas: -> echo "-" > /proc/s390dbf/dasd/flush +> echo "-" > /sys/kernel/debug/s390dbf/dasd/flush + +Changing the size of debug areas +------------------------------------ +It is possible the change the size of debug areas through piping +the number of pages to the debugfs file "pages". The resize request will +also flush the debug areas. + +Example: + +Define 4 pages for the debug areas of debug feature "dasd": +> echo "4" > /sys/kernel/debug/s390dbf/dasd/pages Stooping the debug feature -------------------------- @@ -491,7 +504,7 @@ Defining views -------------- Views are specified with the 'debug_view' structure. There are defined -callback functions which are used for reading and writing the proc files: +callback functions which are used for reading and writing the debugfs files: struct debug_view { char name[DEBUG_MAX_PROCF_LEN]; @@ -525,7 +538,7 @@ typedef int (debug_input_proc_t) (debug_info_t* id, The "private_data" member can be used as pointer to view specific data. It is not used by the debug feature itself. -The output when reading a debug-proc file is structured like this: +The output when reading a debugfs file is structured like this: "prolog_proc output" @@ -534,13 +547,13 @@ The output when reading a debug-proc file is structured like this: "header_proc output 3" "format_proc output 3" ... -When a view is read from the proc fs, the Debug Feature calls the +When a view is read from the debugfs, the Debug Feature calls the 'prolog_proc' once for writing the prolog. Then 'header_proc' and 'format_proc' are called for each existing debug entry. The input_proc can be used to implement functionality when it is written to -the view (e.g. like with 'echo "0" > /proc/s390dbf/dasd/level). +the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level). For header_proc there can be used the default function debug_dflt_header_fn() which is defined in in debug.h. @@ -602,7 +615,7 @@ debug_info = debug_register ("test", 0, 4, 4 )); debug_register_view(debug_info, &debug_test_view); for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i); -> cat /proc/s390dbf/test/myview +> cat /sys/kernel/debug/s390dbf/test/myview 00 00964419734:611402 1 - 00 88042ca This error........... 00 00964419734:611405 1 - 00 88042ca That error........... 00 00964419734:611408 1 - 00 88042ca Problem.............. diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index f98c2e3..136d817 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt @@ -72,6 +72,8 @@ On all - write a character to /proc/sysrq-trigger. eg: 'b' - Will immediately reboot the system without syncing or unmounting your disks. +'c' - Will perform a kexec reboot in order to take a crashdump. + 'o' - Will shut your system off (if configured and supported). 's' - Will attempt to sync all mounted filesystems. @@ -122,6 +124,9 @@ useful when you want to exit a program that will not let you switch consoles. re'B'oot is good when you're unable to shut down. But you should also 'S'ync and 'U'mount first. +'C'rashdump can be used to manually trigger a crashdump when the system is hung. +The kernel needs to have been built with CONFIG_KEXEC enabled. + 'S'ync is great when your system is locked up, it allows you to sync your disks and will certainly lessen the chance of data loss and fscking. Note that the sync hasn't taken place until you see the "OK" and "Done" appear diff --git a/MAINTAINERS b/MAINTAINERS index a07eeb4..a0b0d59 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -576,10 +576,9 @@ S: Supported COMPUTONE INTELLIPORT MULTIPORT CARD P: Michael H. Warfield -M: Michael H. Warfield <mhw@wittsend.com> +M: mhw@wittsend.com W: http://www.wittsend.com/computone.html -L: linux-computone@lazuli.wittsend.com -S: Orphaned +S: Maintained COSA/SRP SYNC SERIAL DRIVER P: Jan "Yenya" Kasprzak @@ -1330,6 +1329,16 @@ M: rml@novell.com L: linux-kernel@vger.kernel.org S: Maintained +KEXEC +P: Eric Biederman +P: Randy Dunlap +M: ebiederm@xmission.com +M: rddunlap@osdl.org +W: http://www.xmission.com/~ebiederm/files/kexec/ +L: linux-kernel@vger.kernel.org +L: fastboot@osdl.org +S: Maintained + LANMEDIA WAN CARD DRIVER P: Andrew Stanley-Jones M: asj@lanmedia.com @@ -2115,9 +2124,7 @@ S: Maintained SOFTWARE SUSPEND: P: Pavel Machek M: pavel@suse.cz -M: pavel@ucw.cz -L: http://lister.fornax.hu/mailman/listinfo/swsusp -W: http://swsusp.sf.net/ +L: linux-pm@osdl.org S: Maintained SONIC NETWORK DRIVER @@ -2594,7 +2601,7 @@ M: davidm@snapgear.com P: D. Jeff Dionne (created first uClinux port) M: jeff@uclinux.org W: http://www.uclinux.org/ -L: uclinux-dev@uclinux.org +L: uclinux-dev@uclinux.org (subscribers-only) S: Maintained UCLINUX FOR NEC V850 @@ -281,7 +281,7 @@ export quiet Q KBUILD_VERBOSE # See documentation in Documentation/kbuild/makefiles.txt # cc-option -# Usage: cflags-y += $(call gcc-option, -march=winchip-c6, -march=i586) +# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586) cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 07ba77c..c8d94dc 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -157,7 +157,7 @@ config ARCH_RPC config ARCH_SA1100 bool "SA1100-based" select ISA - select DISCONTIGMEM + select ARCH_DISCONTIGMEM_ENABLE config ARCH_S3C2410 bool "Samsung S3C2410" @@ -346,6 +346,21 @@ config PREEMPT Say Y here if you are building a kernel for a desktop, embedded or real-time system. Say N if you are unsure. +config NO_IDLE_HZ + bool "Dynamic tick timer" + help + Select this option if you want to disable continuous timer ticks + and have them programmed to occur as required. This option saves + power as the system can remain in idle state for longer. + + By default dynamic tick is disabled during the boot, and can be + manually enabled with: + + echo 1 > /sys/devices/system/timer/timer0/dyn_tick + + Alternatively, if you want dynamic tick automatically enabled + during boot, pass "dyntick=enable" via the kernel command string. + config ARCH_DISCONTIGMEM_ENABLE bool default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM) diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig index 06fae4b..b8c51ee 100644 --- a/arch/arm/configs/enp2611_defconfig +++ b/arch/arm/configs/enp2611_defconfig @@ -1,14 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 22:08:24 2005 +# Linux kernel version: 2.6.12-git6 +# Sat Jun 25 00:57:29 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y # # Code maturity level options @@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # @@ -96,6 +99,7 @@ CONFIG_ARCH_ENP2611=y # CONFIG_ARCH_IXDP2800 is not set # CONFIG_ARCH_IXDP2401 is not set # CONFIG_ARCH_IXDP2801 is not set +# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set # # Processor Type @@ -106,7 +110,6 @@ CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5T=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_TLB_V4WBI=y -CONFIG_CPU_MINICACHE=y # # Processor Features @@ -118,9 +121,11 @@ CONFIG_XSCALE_PMU=y # # Bus support # +CONFIG_ISA_DMA_API=y CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -130,7 +135,15 @@ CONFIG_PCI_NAMES=y # # Kernel Features # +# CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_ALIGNMENT_TRAP=y # @@ -269,7 +282,6 @@ CONFIG_MTD_IXP2000=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -308,6 +320,7 @@ CONFIG_IOSCHED_CFQ=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -329,10 +342,11 @@ CONFIG_NET=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y @@ -349,6 +363,17 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -404,6 +429,7 @@ CONFIG_MII=y # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set # # Tulip family network device support @@ -440,9 +466,11 @@ CONFIG_EEPRO100=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -464,6 +492,7 @@ CONFIG_EEPRO100=y # Wan interfaces # CONFIG_WAN=y +# CONFIG_DSCC4 is not set # CONFIG_LANMEDIA is not set # CONFIG_SYNCLINK_SYNCPPP is not set CONFIG_HDLC=y @@ -526,7 +555,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # # CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -547,6 +575,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -613,17 +642,18 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_IXP2000 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set @@ -637,7 +667,9 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -653,6 +685,7 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -662,14 +695,19 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set CONFIG_SENSORS_EEPROM=y # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -723,6 +761,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y # CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y @@ -763,7 +802,6 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_TMPFS_XATTR is not set @@ -801,12 +839,14 @@ CONFIG_JFFS2_RTIME=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -891,3 +931,4 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig index 810a450..3cfbe2e 100644 --- a/arch/arm/configs/ixdp2400_defconfig +++ b/arch/arm/configs/ixdp2400_defconfig @@ -1,14 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 21:13:38 2005 +# Linux kernel version: 2.6.12-git6 +# Sat Jun 25 00:58:38 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y # # Code maturity level options @@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # @@ -97,6 +100,7 @@ CONFIG_ARCH_IXDP2400=y CONFIG_ARCH_IXDP2X00=y # CONFIG_ARCH_IXDP2401 is not set # CONFIG_ARCH_IXDP2801 is not set +# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set # # Processor Type @@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5T=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_TLB_V4WBI=y -CONFIG_CPU_MINICACHE=y # # Processor Features @@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y # # Bus support # +CONFIG_ISA_DMA_API=y CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y # # Kernel Features # +# CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_ALIGNMENT_TRAP=y # @@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -330,10 +343,11 @@ CONFIG_NET=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y @@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -405,6 +430,7 @@ CONFIG_MII=y # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set # # Tulip family network device support @@ -441,9 +467,11 @@ CONFIG_EEPRO100=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -465,6 +493,7 @@ CONFIG_EEPRO100=y # Wan interfaces # CONFIG_WAN=y +# CONFIG_DSCC4 is not set # CONFIG_LANMEDIA is not set # CONFIG_SYNCLINK_SYNCPPP is not set CONFIG_HDLC=y @@ -527,7 +556,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # # CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -548,6 +576,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -614,17 +643,18 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_IXP2000 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set @@ -638,7 +668,9 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -654,6 +686,7 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -663,14 +696,19 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set CONFIG_SENSORS_EEPROM=y # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -724,6 +762,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y # CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y @@ -764,7 +803,6 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_TMPFS_XATTR is not set @@ -802,12 +840,14 @@ CONFIG_JFFS2_RTIME=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -892,3 +932,4 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig index 72e1b94..5c87e8e 100644 --- a/arch/arm/configs/ixdp2401_defconfig +++ b/arch/arm/configs/ixdp2401_defconfig @@ -1,14 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 21:53:55 2005 +# Linux kernel version: 2.6.12-git6 +# Sat Jun 25 00:59:35 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y # # Code maturity level options @@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # @@ -97,6 +100,7 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y CONFIG_ARCH_IXDP2401=y # CONFIG_ARCH_IXDP2801 is not set CONFIG_ARCH_IXDP2X01=y +# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set # # Processor Type @@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5T=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_TLB_V4WBI=y -CONFIG_CPU_MINICACHE=y # # Processor Features @@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y # # Bus support # +CONFIG_ISA_DMA_API=y CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y # # Kernel Features # +# CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_ALIGNMENT_TRAP=y # @@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -330,10 +343,11 @@ CONFIG_NET=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y @@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set CONFIG_IP_TCPDIAG=y # CONFIG_IP_TCPDIAG_IPV6 is not set + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -405,6 +430,7 @@ CONFIG_MII=y # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set # # Tulip family network device support @@ -442,9 +468,11 @@ CONFIG_EEPRO100=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -466,6 +494,7 @@ CONFIG_EEPRO100=y # Wan interfaces # CONFIG_WAN=y +# CONFIG_DSCC4 is not set # CONFIG_LANMEDIA is not set # CONFIG_SYNCLINK_SYNCPPP is not set CONFIG_HDLC=y @@ -528,7 +557,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # # CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -549,6 +577,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -615,17 +644,18 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_IXP2000 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set @@ -639,7 +669,9 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -655,6 +687,7 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -664,14 +697,19 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set CONFIG_SENSORS_EEPROM=y # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -725,6 +763,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y # CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y @@ -765,7 +804,6 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_TMPFS_XATTR is not set @@ -803,12 +841,14 @@ CONFIG_JFFS2_RTIME=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -893,3 +933,4 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index 1592e45..3cb561a 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -1,14 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 22:15:23 2005 +# Linux kernel version: 2.6.12-git6 +# Sat Jun 25 01:00:27 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y # # Code maturity level options @@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # @@ -97,6 +100,7 @@ CONFIG_ARCH_IXDP2800=y CONFIG_ARCH_IXDP2X00=y # CONFIG_ARCH_IXDP2401 is not set # CONFIG_ARCH_IXDP2801 is not set +# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set # # Processor Type @@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5T=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_TLB_V4WBI=y -CONFIG_CPU_MINICACHE=y # # Processor Features @@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y # # Bus support # +CONFIG_ISA_DMA_API=y CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y # # Kernel Features # +# CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_ALIGNMENT_TRAP=y # @@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -330,10 +343,11 @@ CONFIG_NET=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y @@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -405,6 +430,7 @@ CONFIG_MII=y # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set # # Tulip family network device support @@ -441,9 +467,11 @@ CONFIG_EEPRO100=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -465,6 +493,7 @@ CONFIG_EEPRO100=y # Wan interfaces # CONFIG_WAN=y +# CONFIG_DSCC4 is not set # CONFIG_LANMEDIA is not set # CONFIG_SYNCLINK_SYNCPPP is not set CONFIG_HDLC=y @@ -527,7 +556,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # # CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -548,6 +576,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -614,17 +643,18 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_IXP2000 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set @@ -638,7 +668,9 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -654,6 +686,7 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -663,14 +696,19 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set CONFIG_SENSORS_EEPROM=y # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -724,6 +762,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y # CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y @@ -764,7 +803,6 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_TMPFS_XATTR is not set @@ -802,12 +840,14 @@ CONFIG_JFFS2_RTIME=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -892,3 +932,4 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig index f1afe3d..b1e162f 100644 --- a/arch/arm/configs/ixdp2801_defconfig +++ b/arch/arm/configs/ixdp2801_defconfig @@ -1,14 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 22:39:19 2005 +# Linux kernel version: 2.6.12-git6 +# Sat Jun 25 01:01:18 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y # # Code maturity level options @@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # @@ -97,6 +100,7 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # CONFIG_ARCH_IXDP2401 is not set CONFIG_ARCH_IXDP2801=y CONFIG_ARCH_IXDP2X01=y +# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set # # Processor Type @@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5T=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_TLB_V4WBI=y -CONFIG_CPU_MINICACHE=y # # Processor Features @@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y # # Bus support # +CONFIG_ISA_DMA_API=y CONFIG_PCI=y CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support @@ -131,7 +136,15 @@ CONFIG_PCI_NAMES=y # # Kernel Features # +# CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_ALIGNMENT_TRAP=y # @@ -270,7 +283,6 @@ CONFIG_MTD_IXP2000=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -309,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -330,10 +343,11 @@ CONFIG_NET=y # CONFIG_PACKET=y CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y +CONFIG_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y @@ -350,6 +364,17 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -405,6 +430,7 @@ CONFIG_MII=y # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set # # Tulip family network device support @@ -442,9 +468,11 @@ CONFIG_EEPRO100=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set # # Ethernet (10000 Mbit) @@ -466,6 +494,7 @@ CONFIG_EEPRO100=y # Wan interfaces # CONFIG_WAN=y +# CONFIG_DSCC4 is not set # CONFIG_LANMEDIA is not set # CONFIG_SYNCLINK_SYNCPPP is not set CONFIG_HDLC=y @@ -528,7 +557,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # # CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -549,6 +577,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -615,17 +644,18 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_IXP2000 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set @@ -639,7 +669,9 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -655,6 +687,7 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -664,14 +697,19 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set CONFIG_SENSORS_EEPROM=y # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -725,6 +763,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y # CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y @@ -765,7 +804,6 @@ CONFIG_DNOTIFY=y # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_TMPFS_XATTR is not set @@ -803,12 +841,14 @@ CONFIG_JFFS2_RTIME=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set # CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -893,3 +933,4 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ff187f4..395137a 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -4,6 +4,10 @@ * Copyright (C) 1992 Linus Torvalds * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. * + * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation. + * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and + * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -37,6 +41,7 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/mach/irq.h> +#include <asm/mach/time.h> /* * Maximum IRQ count. Currently, this is arbitary. However, it should @@ -329,6 +334,15 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) spin_unlock(&irq_controller_lock); +#ifdef CONFIG_NO_IDLE_HZ + if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) { + write_seqlock(&xtime_lock); + if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) + system_timer->dyn_tick->handler(irq, 0, regs); + write_sequnlock(&xtime_lock); + } +#endif + if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 07ddeed61..5e435e4 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -697,7 +697,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (!user_mode(regs)) return 0; - if (try_to_freeze(0)) + if (try_to_freeze()) goto no_signal; if (current->ptrace & PT_SINGLESTEP) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index c232f24..06054c9 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -381,6 +381,95 @@ static struct sysdev_class timer_sysclass = { .resume = timer_resume, }; +#ifdef CONFIG_NO_IDLE_HZ +static int timer_dyn_tick_enable(void) +{ + struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; + unsigned long flags; + int ret = -ENODEV; + + if (dyn_tick) { + write_seqlock_irqsave(&xtime_lock, flags); + ret = 0; + if (!(dyn_tick->state & DYN_TICK_ENABLED)) { + ret = dyn_tick->enable(); + + if (ret == 0) + dyn_tick->state |= DYN_TICK_ENABLED; + } + write_sequnlock_irqrestore(&xtime_lock, flags); + } + + return ret; +} + +static int timer_dyn_tick_disable(void) +{ + struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; + unsigned long flags; + int ret = -ENODEV; + + if (dyn_tick) { + write_seqlock_irqsave(&xtime_lock, flags); + ret = 0; + if (dyn_tick->state & DYN_TICK_ENABLED) { + ret = dyn_tick->disable(); + + if (ret == 0) + dyn_tick->state &= ~DYN_TICK_ENABLED; + } + write_sequnlock_irqrestore(&xtime_lock, flags); + } + + return ret; +} + +void timer_dyn_reprogram(void) +{ + struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; + unsigned long flags; + + write_seqlock_irqsave(&xtime_lock, flags); + if (dyn_tick->state & DYN_TICK_ENABLED) + dyn_tick->reprogram(next_timer_interrupt() - jiffies); + write_sequnlock_irqrestore(&xtime_lock, flags); +} + +static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "%i\n", + (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1); +} + +static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf, + size_t count) +{ + unsigned int enable = simple_strtoul(buf, NULL, 2); + + if (enable) + timer_dyn_tick_enable(); + else + timer_dyn_tick_disable(); + + return count; +} +static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); + +/* + * dyntick=enable|disable + */ +static char dyntick_str[4] __initdata = ""; + +static int __init dyntick_setup(char *str) +{ + if (str) + strlcpy(dyntick_str, str, sizeof(dyntick_str)); + return 1; +} + +__setup("dyntick=", dyntick_setup); +#endif + static int __init timer_init_sysfs(void) { int ret = sysdev_class_register(&timer_sysclass); @@ -388,6 +477,20 @@ static int __init timer_init_sysfs(void) system_timer->dev.cls = &timer_sysclass; ret = sysdev_register(&system_timer->dev); } + +#ifdef CONFIG_NO_IDLE_HZ + if (ret == 0 && system_timer->dyn_tick) { + ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick); + + /* + * Turn on dynamic tick after calibrate delay + * for correct bogomips + */ + if (ret == 0 && dyntick_str[0] == 'e') + ret = timer_dyn_tick_enable(); + } +#endif + return ret; } diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig index 45c930c..0793dcf 100644 --- a/arch/arm/mach-clps711x/Kconfig +++ b/arch/arm/mach-clps711x/Kconfig @@ -28,7 +28,7 @@ config ARCH_CLEP7312 config ARCH_EDB7211 bool "EDB7211" select ISA - select DISCONTIGMEM + select ARCH_DISCONTIGMEM_ENABLE help Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211 evaluation board. diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig index 9361e05..ecb58d8 100644 --- a/arch/arm/mach-ixp2000/Kconfig +++ b/arch/arm/mach-ixp2000/Kconfig @@ -54,6 +54,14 @@ config ARCH_IXDP2X01 depends on ARCH_IXDP2401 || ARCH_IXDP2801 default y +config IXP2000_SUPPORT_BROKEN_PCI_IO + bool "Support broken PCI I/O on older IXP2000s" + default y + help + Say 'N' here if you only intend to run your kernel on an + IXP2000 B0 or later model and do not need the PCI I/O + byteswap workaround. Say 'Y' otherwise. + endmenu endif diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index 04b38bc..f3a291b 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c @@ -197,8 +197,23 @@ static struct platform_device enp2611_flash = { .resource = &enp2611_flash_resource, }; +static struct ixp2000_i2c_pins enp2611_i2c_gpio_pins = { + .sda_pin = ENP2611_GPIO_SDA, + .scl_pin = ENP2611_GPIO_SCL, +}; + +static struct platform_device enp2611_i2c_controller = { + .name = "IXP2000-I2C", + .id = 0, + .dev = { + .platform_data = &enp2611_i2c_gpio_pins + }, + .num_resources = 0 +}; + static struct platform_device *enp2611_devices[] __initdata = { - &enp2611_flash + &enp2611_flash, + &enp2611_i2c_controller }; static void __init enp2611_init_machine(void) diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 21c41fe..5e43807 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -42,6 +42,9 @@ #include <asm/mach/flash.h> #include <asm/mach/arch.h> +#include <asm/arch/gpio.h> + + /************************************************************************* * IXDP2x00 IRQ Initialization *************************************************************************/ diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 5ff2f27..0788fb2 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c @@ -198,6 +198,19 @@ clear_master_aborts(void) void __init ixp2000_pci_preinit(void) { +#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO + /* + * Configure the PCI unit to properly byteswap I/O transactions, + * and verify that it worked. + */ + ixp2000_reg_write(IXP2000_PCI_CONTROL, + (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE)); + + if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0) + panic("IXP2000: PCI I/O is broken on this ixp model, and " + "the needed workaround has not been configured in"); +#endif + hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, "PCI config cycle to non-existent device"); } diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index ef6865f..767ebb5 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c @@ -790,12 +790,10 @@ void __init setup_arch(char **cmdline_p) #ifndef CONFIG_GDBSTUB_UART0 __reg(UART0_BASE + UART_IER * 8) = 0; early_serial_setup(&__frv_uart0); -// register_serial(&__frv_uart0); #endif #ifndef CONFIG_GDBSTUB_UART1 __reg(UART1_BASE + UART_IER * 8) = 0; early_serial_setup(&__frv_uart1); -// register_serial(&__frv_uart1); #endif #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index d8d8f3d..36a2dff 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -536,10 +536,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } if (!oldset) oldset = ¤t->blocked; diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index a4799d6..5aab87e 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -517,10 +517,8 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) if ((regs->ccr & 0x10)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } current->thread.esp0 = (unsigned long) regs; diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index d4ae5f9..6c02336 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -510,28 +510,7 @@ config SCHED_SMT cost of slightly increased overhead in some places. If unsure say N here. -config PREEMPT - bool "Preemptible Kernel" - help - This option reduces the latency of the kernel when reacting to - real-time or interactive events by allowing a low priority process to - be preempted even if it is in kernel mode executing a system call. - This allows applications to run more reliably even when the system is - under load. - - Say Y here if you are building a kernel for a desktop, embedded - or real-time system. Say N if you are unsure. - -config PREEMPT_BKL - bool "Preempt The Big Kernel Lock" - depends on PREEMPT - default y - help - This option reduces the latency of the kernel by making the - big kernel lock preemptible. - - Say Y here if you are building a kernel for a desktop system. - Say N if you are unsure. +source "kernel/Kconfig.preempt" config X86_UP_APIC bool "Local APIC support on uniprocessors" @@ -963,6 +942,41 @@ config SECCOMP source kernel/Kconfig.hz +config PHYSICAL_START + hex "Physical address where the kernel is loaded" if EMBEDDED + default "0x100000" + help + This gives the physical address where the kernel is loaded. + Primarily used in the case of kexec on panic where the + fail safe kernel needs to run at a different address than + the panic-ed kernel. + + Don't change this unless you know what you are doing. + +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + +config CRASH_DUMP + bool "kernel crash dumps (EXPERIMENTAL)" + depends on EMBEDDED + depends on EXPERIMENTAL + depends on HIGHMEM + help + Generate crash dump after being started by kexec. endmenu @@ -1250,6 +1264,15 @@ config SCx200 This support is also available as a module. If compiled as a module, it will be called scx200. +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + depends on SMP && HOTPLUG && EXPERIMENTAL + ---help--- + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu. + + Say N. + source "drivers/pcmcia/Kconfig" source "drivers/pci/hotplug/Kconfig" diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile index 43cd622..1e71382 100644 --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -25,8 +25,8 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA #RAMDISK := -DRAMDISK=512 -targets := vmlinux.bin bootsect bootsect.o setup setup.o \ - zImage bzImage +targets := vmlinux.bin bootsect bootsect.o \ + setup setup.o zImage bzImage subdir- := compressed hostprogs-y := tools/build diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S index c5e80b6..b5893e4 100644 --- a/arch/i386/boot/compressed/head.S +++ b/arch/i386/boot/compressed/head.S @@ -25,6 +25,7 @@ #include <linux/linkage.h> #include <asm/segment.h> +#include <asm/page.h> .globl startup_32 @@ -74,7 +75,7 @@ startup_32: popl %esi # discard address popl %esi # real mode pointer xorl %ebx,%ebx - ljmp $(__BOOT_CS), $0x100000 + ljmp $(__BOOT_CS), $__PHYSICAL_START /* * We come here, if we were loaded high. @@ -99,7 +100,7 @@ startup_32: popl %ecx # lcount popl %edx # high_buffer_start popl %eax # hcount - movl $0x100000,%edi + movl $__PHYSICAL_START,%edi cli # make sure we don't get interrupted ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine @@ -124,5 +125,5 @@ move_routine_start: movsl movl %ebx,%esi # Restore setup pointer xorl %ebx,%ebx - ljmp $(__BOOT_CS), $0x100000 + ljmp $(__BOOT_CS), $__PHYSICAL_START move_routine_end: diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c index cedc55c..82a807f 100644 --- a/arch/i386/boot/compressed/misc.c +++ b/arch/i386/boot/compressed/misc.c @@ -13,6 +13,7 @@ #include <linux/vmalloc.h> #include <linux/tty.h> #include <asm/io.h> +#include <asm/page.h> /* * gzip declarations @@ -308,7 +309,7 @@ static void setup_normal_output_buffer(void) #else if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory"); #endif - output_data = (char *)0x100000; /* Points to 1M */ + output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */ free_mem_end_ptr = (long)real_mode; } @@ -333,8 +334,8 @@ static void setup_output_buffer_if_we_run_high(struct moveparams *mv) low_buffer_size = low_buffer_end - LOW_BUFFER_START; high_loaded = 1; free_mem_end_ptr = (long)high_buffer_start; - if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { - high_buffer_start = (uch *)(0x100000 + low_buffer_size); + if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { + high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); mv->hcount = 0; /* say: we need not to move high_buffer */ } else mv->hcount = -1; @@ -353,7 +354,6 @@ static void close_output_buffer_if_we_run_high(struct moveparams *mv) } } - asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) { real_mode = rmode; diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S index 027d6b3..d8d69f2 100644 --- a/arch/i386/boot/edd.S +++ b/arch/i386/boot/edd.S @@ -6,7 +6,7 @@ * projects 1572D, 1484D, 1386D, 1226DT * disk signature read by Matt Domsch <Matt_Domsch@dell.com> * and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004 - * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net> + * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net> * March 2004 * Command line option parsing, Matt Domsch, November 2004 */ diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index caa1fde..8cb420f 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -33,7 +33,7 @@ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * <stiker@northlink.com> * - * Fix to work around buggy BIOSes which dont use carry bit correctly + * Fix to work around buggy BIOSes which don't use carry bit correctly * and/or report extended memory in CX/DX for e801h memory size detection * call. As a result the kernel got wrong figures. The int15/e801h docs * from Ralf Brown interrupt list seem to indicate AX/BX should be used @@ -357,7 +357,7 @@ bail820: meme801: stc # fix to work around buggy - xorw %cx,%cx # BIOSes which dont clear/set + xorw %cx,%cx # BIOSes which don't clear/set xorw %dx,%dx # carry on pass/error of # e801h memory size call # or merely pass cx,dx though @@ -847,7 +847,7 @@ flush_instr: # # but we yet haven't reloaded the CS register, so the default size # of the target offset still is 16 bit. -# However, using an operand prefix (0x66), the CPU will properly +# However, using an operand prefix (0x66), the CPU will properly # take our 48 bit far pointer. (INTeL 80386 Programmer's Reference # Manual, Mixing 16-bit and 32-bit code, page 16-6) diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c index 26509b8..4a17956 100644 --- a/arch/i386/boot/tools/build.c +++ b/arch/i386/boot/tools/build.c @@ -1,6 +1,4 @@ /* - * $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $ - * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1997 Martin Mares */ @@ -8,7 +6,8 @@ /* * This file builds a disk-image from three different files: * - * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - bootsect: compatibility mbr which prints an error message if + * someone tries to boot the kernel directly. * - setup: 8086 machine code, sets up system parm * - system: 80386 code for actual system * diff --git a/arch/i386/crypto/aes.c b/arch/i386/crypto/aes.c index 1019430..88ee85c 100644 --- a/arch/i386/crypto/aes.c +++ b/arch/i386/crypto/aes.c @@ -59,7 +59,7 @@ struct aes_ctx { }; #define WPOLY 0x011b -#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) +#define u32_in(x) le32_to_cpup((const __le32 *)(x)) #define bytes2word(b0, b1, b2, b3) \ (((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0)) diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 28e6203..ca07b95 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -126,7 +126,6 @@ CONFIG_HAVE_DEC_LOCK=y # CONFIG_PM=y CONFIG_SOFTWARE_SUSPEND=y -# CONFIG_PM_DISK is not set # # ACPI (Advanced Configuration and Power Interface) Support diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 51ecd51..4cc83b3 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o obj-$(CONFIG_KPROBES) += kprobes.o diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 848bb97..9f63ae0 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -29,6 +29,7 @@ #include <linux/efi.h> #include <linux/irq.h> #include <linux/module.h> +#include <linux/dmi.h> #include <asm/pgtable.h> #include <asm/io_apic.h> @@ -815,6 +816,219 @@ acpi_process_madt(void) return; } +extern int acpi_force; + +#ifdef __i386__ + +#ifdef CONFIG_ACPI_PCI +static int __init disable_acpi_irq(struct dmi_system_id *d) +{ + if (!acpi_force) { + printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n", + d->ident); + acpi_noirq_set(); + } + return 0; +} + +static int __init disable_acpi_pci(struct dmi_system_id *d) +{ + if (!acpi_force) { + printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", + d->ident); + acpi_disable_pci(); + } + return 0; +} +#endif + +static int __init dmi_disable_acpi(struct dmi_system_id *d) +{ + if (!acpi_force) { + printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); + disable_acpi(); + } else { + printk(KERN_NOTICE + "Warning: DMI blacklist says broken, but acpi forced\n"); + } + return 0; +} + +/* + * Limit ACPI to CPU enumeration for HT + */ +static int __init force_acpi_ht(struct dmi_system_id *d) +{ + if (!acpi_force) { + printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); + disable_acpi(); + acpi_ht = 1; + } else { + printk(KERN_NOTICE + "Warning: acpi=force overrules DMI blacklist: acpi=ht\n"); + } + return 0; +} + +/* + * If your system is blacklisted here, but you find that acpi=force + * works for you, please contact acpi-devel@sourceforge.net + */ +static struct dmi_system_id __initdata acpi_dmi_table[] = { + /* + * Boxes that need ACPI disabled + */ + { + .callback = dmi_disable_acpi, + .ident = "IBM Thinkpad", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_BOARD_NAME, "2629H1G"), + }, + }, + + /* + * Boxes that need acpi=ht + */ + { + .callback = force_acpi_ht, + .ident = "FSC Primergy T850", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "DELL GX240", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "HP VISUALIZE NT Workstation", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "Compaq Workstation W8000", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "ASUS P4B266", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "P4B266"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "ASUS P2B-DS", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "ASUS CUR-DLS", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "ABIT i440BX-W83977", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"), + DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "IBM Bladecenter", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "IBM eServer xSeries 360", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "IBM eserver xSeries 330", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"), + }, + }, + { + .callback = force_acpi_ht, + .ident = "IBM eserver xSeries 440", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), + DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"), + }, + }, + +#ifdef CONFIG_ACPI_PCI + /* + * Boxes that need ACPI PCI IRQ routing disabled + */ + { + .callback = disable_acpi_irq, + .ident = "ASUS A7V", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"), + DMI_MATCH(DMI_BOARD_NAME, "<A7V>"), + /* newer BIOS, Revision 1011, does work */ + DMI_MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"), + }, + }, + + /* + * Boxes that need ACPI PCI IRQ routing and PCI scan disabled + */ + { /* _BBN 0 bug */ + .callback = disable_acpi_pci, + .ident = "ASUS PR-DLS", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"), + DMI_MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"), + DMI_MATCH(DMI_BIOS_DATE, "03/21/2003") + }, + }, + { + .callback = disable_acpi_pci, + .ident = "Acer TravelMate 36x Laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), + }, + }, +#endif + { } +}; + +#endif /* __i386__ */ + /* * acpi_boot_table_init() and acpi_boot_init() * called from setup_arch(), always. @@ -843,6 +1057,10 @@ acpi_boot_table_init(void) { int error; +#ifdef __i386__ + dmi_check_system(acpi_dmi_table); +#endif + /* * If acpi_disabled, bail out * One exception: acpi=ht continues far enough to enumerate LAPICs @@ -870,8 +1088,6 @@ acpi_boot_table_init(void) */ error = acpi_blacklisted(); if (error) { - extern int acpi_force; - if (acpi_force) { printk(KERN_WARNING PREFIX "acpi=force override\n"); } else { diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c index 28bb051..c1af930 100644 --- a/arch/i386/kernel/acpi/sleep.c +++ b/arch/i386/kernel/acpi/sleep.c @@ -7,6 +7,7 @@ #include <linux/acpi.h> #include <linux/bootmem.h> +#include <linux/dmi.h> #include <asm/smp.h> #include <asm/tlbflush.h> @@ -91,3 +92,29 @@ static int __init acpi_sleep_setup(char *str) __setup("acpi_sleep=", acpi_sleep_setup); + + +static __init int reset_videomode_after_s3(struct dmi_system_id *d) +{ + acpi_video_flags |= 2; + return 0; +} + +static __initdata struct dmi_system_id acpisleep_dmi_table[] = { + { /* Reset video mode after returning from ACPI S3 sleep */ + .callback = reset_videomode_after_s3, + .ident = "Toshiba Satellite 4030cdt", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), + }, + }, + { } +}; + +static int __init acpisleep_dmi_init(void) +{ + dmi_check_system(acpisleep_dmi_table); + return 0; +} + +core_initcall(acpisleep_dmi_init); diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 8d993fa..93df90b 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -26,6 +26,7 @@ #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> #include <linux/sysdev.h> +#include <linux/cpu.h> #include <asm/atomic.h> #include <asm/smp.h> @@ -40,6 +41,11 @@ #include "io_ports.h" /* + * Knob to control our willingness to enable the local APIC. + */ +int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ + +/* * Debug level */ int apic_verbosity; @@ -205,7 +211,7 @@ void __init connect_bsp_APIC(void) enable_apic_mode(); } -void disconnect_bsp_APIC(void) +void disconnect_bsp_APIC(int virt_wire_setup) { if (pic_mode) { /* @@ -219,6 +225,42 @@ void disconnect_bsp_APIC(void) outb(0x70, 0x22); outb(0x00, 0x23); } + else { + /* Go back to Virtual Wire compatibility mode */ + unsigned long value; + + /* For the spurious interrupt use vector F, and enable it */ + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; + value |= APIC_SPIV_APIC_ENABLED; + value |= 0xf; + apic_write_around(APIC_SPIV, value); + + if (!virt_wire_setup) { + /* For LVT0 make it edge triggered, active high, external and enabled */ + value = apic_read(APIC_LVT0); + value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); + apic_write_around(APIC_LVT0, value); + } + else { + /* Disable LVT0 */ + apic_write_around(APIC_LVT0, APIC_LVT_MASKED); + } + + /* For LVT1 make it edge triggered, active high, nmi and enabled */ + value = apic_read(APIC_LVT1); + value &= ~( + APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); + apic_write_around(APIC_LVT1, value); + } } void disable_local_APIC(void) @@ -363,7 +405,7 @@ void __init init_bsp_APIC(void) apic_write_around(APIC_LVT1, value); } -void __init setup_local_APIC (void) +void __devinit setup_local_APIC(void) { unsigned long oldvalue, value, ver, maxlvt; @@ -634,7 +676,7 @@ static struct sys_device device_lapic = { .cls = &lapic_sysclass, }; -static void __init apic_pm_activate(void) +static void __devinit apic_pm_activate(void) { apic_pm_state.active = 1; } @@ -665,26 +707,6 @@ static void apic_pm_activate(void) { } * Original code written by Keir Fraser. */ -/* - * Knob to control our willingness to enable the local APIC. - */ -int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ - -static int __init lapic_disable(char *str) -{ - enable_local_apic = -1; - clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); - return 0; -} -__setup("nolapic", lapic_disable); - -static int __init lapic_enable(char *str) -{ - enable_local_apic = 1; - return 0; -} -__setup("lapic", lapic_enable); - static int __init apic_set_verbosity(char *str) { if (strcmp("debug", str) == 0) @@ -855,7 +877,7 @@ fake_ioapic_page: * but we do not accept timer interrupts yet. We only allow the BP * to calibrate. */ -static unsigned int __init get_8254_timer_count(void) +static unsigned int __devinit get_8254_timer_count(void) { extern spinlock_t i8253_lock; unsigned long flags; @@ -874,7 +896,7 @@ static unsigned int __init get_8254_timer_count(void) } /* next tick in 8254 can be caught by catching timer wraparound */ -static void __init wait_8254_wraparound(void) +static void __devinit wait_8254_wraparound(void) { unsigned int curr_count, prev_count; @@ -894,7 +916,7 @@ static void __init wait_8254_wraparound(void) * Default initialization for 8254 timers. If we use other timers like HPET, * we override this later */ -void (*wait_timer_tick)(void) __initdata = wait_8254_wraparound; +void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound; /* * This function sets up the local APIC timer, with a timeout of @@ -930,7 +952,7 @@ static void __setup_APIC_LVTT(unsigned int clocks) apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); } -static void __init setup_APIC_timer(unsigned int clocks) +static void __devinit setup_APIC_timer(unsigned int clocks) { unsigned long flags; @@ -1043,12 +1065,12 @@ void __init setup_boot_APIC_clock(void) local_irq_enable(); } -void __init setup_secondary_APIC_clock(void) +void __devinit setup_secondary_APIC_clock(void) { setup_APIC_timer(calibration_result); } -void __init disable_APIC_timer(void) +void __devinit disable_APIC_timer(void) { if (using_apic_timer) { unsigned long v; diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 0ff65ab..d48ce92 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -346,10 +346,10 @@ extern int (*console_blank_hook)(int); struct apm_user { int magic; struct apm_user * next; - int suser: 1; - int writer: 1; - int reader: 1; - int suspend_wait: 1; + unsigned int suser: 1; + unsigned int writer: 1; + unsigned int reader: 1; + unsigned int suspend_wait: 1; int suspend_result; int suspends_pending; int standbys_pending; diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index b995424..2203a9d 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -24,9 +24,9 @@ EXPORT_PER_CPU_SYMBOL(cpu_gdt_table); DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); -static int cachesize_override __initdata = -1; -static int disable_x86_fxsr __initdata = 0; -static int disable_x86_serial_nr __initdata = 1; +static int cachesize_override __devinitdata = -1; +static int disable_x86_fxsr __devinitdata = 0; +static int disable_x86_serial_nr __devinitdata = 1; struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; @@ -59,7 +59,7 @@ static int __init cachesize_setup(char *str) } __setup("cachesize=", cachesize_setup); -int __init get_model_name(struct cpuinfo_x86 *c) +int __devinit get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; char *p, *q; @@ -89,7 +89,7 @@ int __init get_model_name(struct cpuinfo_x86 *c) } -void __init display_cacheinfo(struct cpuinfo_x86 *c) +void __devinit display_cacheinfo(struct cpuinfo_x86 *c) { unsigned int n, dummy, ecx, edx, l2size; @@ -130,7 +130,7 @@ void __init display_cacheinfo(struct cpuinfo_x86 *c) /* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */ /* Look up CPU names by table lookup. */ -static char __init *table_lookup_model(struct cpuinfo_x86 *c) +static char __devinit *table_lookup_model(struct cpuinfo_x86 *c) { struct cpu_model_info *info; @@ -151,7 +151,7 @@ static char __init *table_lookup_model(struct cpuinfo_x86 *c) } -void __init get_cpu_vendor(struct cpuinfo_x86 *c, int early) +void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early) { char *v = c->x86_vendor_id; int i; @@ -202,7 +202,7 @@ static inline int flag_is_changeable_p(u32 flag) /* Probe for the CPUID instruction */ -static int __init have_cpuid_p(void) +static int __devinit have_cpuid_p(void) { return flag_is_changeable_p(X86_EFLAGS_ID); } @@ -249,7 +249,7 @@ static void __init early_cpu_detect(void) #endif } -void __init generic_identify(struct cpuinfo_x86 * c) +void __devinit generic_identify(struct cpuinfo_x86 * c) { u32 tfms, xlvl; int junk; @@ -296,7 +296,7 @@ void __init generic_identify(struct cpuinfo_x86 * c) } } -static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c) +static void __devinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c) { if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) { /* Disable processor serial number */ @@ -324,7 +324,7 @@ __setup("serialnumber", x86_serial_nr_setup); /* * This does the hard work of actually picking apart the CPU stuff... */ -void __init identify_cpu(struct cpuinfo_x86 *c) +void __devinit identify_cpu(struct cpuinfo_x86 *c) { int i; @@ -432,10 +432,13 @@ void __init identify_cpu(struct cpuinfo_x86 *c) #ifdef CONFIG_X86_MCE mcheck_init(c); #endif + if (c == &boot_cpu_data) + sysenter_setup(); + enable_sep_cpu(); } #ifdef CONFIG_X86_HT -void __init detect_ht(struct cpuinfo_x86 *c) +void __devinit detect_ht(struct cpuinfo_x86 *c) { u32 eax, ebx, ecx, edx; int index_msb, tmp; @@ -490,7 +493,7 @@ void __init detect_ht(struct cpuinfo_x86 *c) } #endif -void __init print_cpu_info(struct cpuinfo_x86 *c) +void __devinit print_cpu_info(struct cpuinfo_x86 *c) { char *vendor = NULL; @@ -513,7 +516,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c) printk("\n"); } -cpumask_t cpu_initialized __initdata = CPU_MASK_NONE; +cpumask_t cpu_initialized __devinitdata = CPU_MASK_NONE; /* This is hacky. :) * We're emulating future behavior. @@ -560,7 +563,7 @@ void __init early_cpu_init(void) * and IDT. We reload them nevertheless, this function acts as a * 'CPU state barrier', nothing should get across. */ -void __init cpu_init (void) +void __devinit cpu_init(void) { int cpu = smp_processor_id(); struct tss_struct * t = &per_cpu(init_tss, cpu); @@ -648,3 +651,15 @@ void __init cpu_init (void) clear_used_math(); mxcsr_feature_mask_init(); } + +#ifdef CONFIG_HOTPLUG_CPU +void __devinit cpu_uninit(void) +{ + int cpu = raw_smp_processor_id(); + cpu_clear(cpu, cpu_initialized); + + /* lazy TLB state */ + per_cpu(cpu_tlbstate, cpu).state = 0; + per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm; +} +#endif diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 5c53006..73a5dc5 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -648,9 +648,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) { } #endif - if (powernow_table) - kfree(powernow_table); - + kfree(powernow_table); return 0; } diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index 121aa21..96a75d0 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -28,7 +28,7 @@ extern int trap_init_f00f_bug(void); struct movsl_mask movsl_mask; #endif -void __init early_intel_workaround(struct cpuinfo_x86 *c) +void __devinit early_intel_workaround(struct cpuinfo_x86 *c) { if (c->x86_vendor != X86_VENDOR_INTEL) return; @@ -43,7 +43,7 @@ void __init early_intel_workaround(struct cpuinfo_x86 *c) * This is called before we do cpu ident work */ -int __init ppro_with_ram_bug(void) +int __devinit ppro_with_ram_bug(void) { /* Uses data from early_cpu_detect now */ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && @@ -61,7 +61,7 @@ int __init ppro_with_ram_bug(void) * P4 Xeon errata 037 workaround. * Hardware prefetcher may cause stale data to be loaded into the cache. */ -static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c) +static void __devinit Intel_errata_workarounds(struct cpuinfo_x86 *c) { unsigned long lo, hi; @@ -80,7 +80,7 @@ static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c) /* * find out the number of processor cores on the die */ -static int __init num_cpu_cores(struct cpuinfo_x86 *c) +static int __devinit num_cpu_cores(struct cpuinfo_x86 *c) { unsigned int eax; @@ -98,7 +98,7 @@ static int __init num_cpu_cores(struct cpuinfo_x86 *c) return 1; } -static void __init init_intel(struct cpuinfo_x86 *c) +static void __devinit init_intel(struct cpuinfo_x86 *c) { unsigned int l2 = 0; char *p = NULL; @@ -204,7 +204,7 @@ static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size) return size; } -static struct cpu_dev intel_cpu_dev __initdata = { +static struct cpu_dev intel_cpu_dev __devinitdata = { .c_vendor = "Intel", .c_ident = { "GenuineIntel" }, .c_models = { diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c index a710dc4..1d768b2 100644 --- a/arch/i386/kernel/cpu/intel_cacheinfo.c +++ b/arch/i386/kernel/cpu/intel_cacheinfo.c @@ -28,7 +28,7 @@ struct _cache_table }; /* all the cache descriptor types we care about (no TLB or trace cache entries) */ -static struct _cache_table cache_table[] __initdata = +static struct _cache_table cache_table[] __devinitdata = { { 0x06, LVL_1_INST, 8 }, /* 4-way set assoc, 32 byte line size */ { 0x08, LVL_1_INST, 16 }, /* 4-way set assoc, 32 byte line size */ @@ -160,7 +160,7 @@ static int __init find_num_cache_leaves(void) return retval; } -unsigned int __init init_intel_cacheinfo(struct cpuinfo_x86 *c) +unsigned int __devinit init_intel_cacheinfo(struct cpuinfo_x86 *c) { unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c index 8df52e8..c4abe76 100644 --- a/arch/i386/kernel/cpu/mcheck/k7.c +++ b/arch/i386/kernel/cpu/mcheck/k7.c @@ -69,7 +69,7 @@ static fastcall void k7_machine_check(struct pt_regs * regs, long error_code) /* AMD K7 machine check is Intel like */ -void __init amd_mcheck_init(struct cpuinfo_x86 *c) +void __devinit amd_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c index bf6d1ae..2cf25d2 100644 --- a/arch/i386/kernel/cpu/mcheck/mce.c +++ b/arch/i386/kernel/cpu/mcheck/mce.c @@ -16,7 +16,7 @@ #include "mce.h" -int mce_disabled __initdata = 0; +int mce_disabled __devinitdata = 0; int nr_mce_banks; EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */ @@ -31,7 +31,7 @@ static fastcall void unexpected_machine_check(struct pt_regs * regs, long error_ void fastcall (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; /* This has to be run for each processor */ -void __init mcheck_init(struct cpuinfo_x86 *c) +void __devinit mcheck_init(struct cpuinfo_x86 *c) { if (mce_disabled==1) return; diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c index 8b16ceb..0abccb6 100644 --- a/arch/i386/kernel/cpu/mcheck/p4.c +++ b/arch/i386/kernel/cpu/mcheck/p4.c @@ -78,7 +78,7 @@ fastcall void smp_thermal_interrupt(struct pt_regs *regs) } /* P4/Xeon Thermal regulation detect and init */ -static void __init intel_init_thermal(struct cpuinfo_x86 *c) +static void __devinit intel_init_thermal(struct cpuinfo_x86 *c) { u32 l, h; unsigned int cpu = smp_processor_id(); @@ -232,7 +232,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) } -void __init intel_p4_mcheck_init(struct cpuinfo_x86 *c) +void __devinit intel_p4_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; diff --git a/arch/i386/kernel/cpu/mcheck/p5.c b/arch/i386/kernel/cpu/mcheck/p5.c index c45a1b4..ec0614c 100644 --- a/arch/i386/kernel/cpu/mcheck/p5.c +++ b/arch/i386/kernel/cpu/mcheck/p5.c @@ -29,7 +29,7 @@ static fastcall void pentium_machine_check(struct pt_regs * regs, long error_cod } /* Set up machine check reporting for processors with Intel style MCE */ -void __init intel_p5_mcheck_init(struct cpuinfo_x86 *c) +void __devinit intel_p5_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; diff --git a/arch/i386/kernel/cpu/mcheck/p6.c b/arch/i386/kernel/cpu/mcheck/p6.c index 46640f8..f01b73f 100644 --- a/arch/i386/kernel/cpu/mcheck/p6.c +++ b/arch/i386/kernel/cpu/mcheck/p6.c @@ -80,7 +80,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) } /* Set up machine check reporting for processors with Intel style MCE */ -void __init intel_p6_mcheck_init(struct cpuinfo_x86 *c) +void __devinit intel_p6_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; diff --git a/arch/i386/kernel/cpu/mcheck/winchip.c b/arch/i386/kernel/cpu/mcheck/winchip.c index 753fa7a..7bae68f 100644 --- a/arch/i386/kernel/cpu/mcheck/winchip.c +++ b/arch/i386/kernel/cpu/mcheck/winchip.c @@ -23,7 +23,7 @@ static fastcall void winchip_machine_check(struct pt_regs * regs, long error_cod } /* Set up machine check reporting on the Winchip C6 series */ -void __init winchip_mcheck_init(struct cpuinfo_x86 *c) +void __devinit winchip_mcheck_init(struct cpuinfo_x86 *c) { u32 lo, hi; machine_check_vector = winchip_machine_check; diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c index f468a97..64d91f7 100644 --- a/arch/i386/kernel/cpu/mtrr/generic.c +++ b/arch/i386/kernel/cpu/mtrr/generic.c @@ -70,8 +70,7 @@ void __init get_mtrr_state(void) /* Free resources associated with a struct mtrr_state */ void __init finalize_mtrr_state(void) { - if (mtrr_state.var_ranges) - kfree(mtrr_state.var_ranges); + kfree(mtrr_state.var_ranges); mtrr_state.var_ranges = NULL; } diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c new file mode 100644 index 0000000..e5fab12 --- /dev/null +++ b/arch/i386/kernel/crash.c @@ -0,0 +1,223 @@ +/* + * Architecture specific (i386) functions for kexec based crash dumps. + * + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * + * Copyright (C) IBM Corporation, 2004. All rights reserved. + * + */ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/smp.h> +#include <linux/irq.h> +#include <linux/reboot.h> +#include <linux/kexec.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/elf.h> +#include <linux/elfcore.h> + +#include <asm/processor.h> +#include <asm/hardirq.h> +#include <asm/nmi.h> +#include <asm/hw_irq.h> +#include <asm/apic.h> +#include <mach_ipi.h> + + +note_buf_t crash_notes[NR_CPUS]; +/* This keeps a track of which one is crashing cpu. */ +static int crashing_cpu; + +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, + size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) +3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +static void crash_save_this_cpu(struct pt_regs *regs, int cpu) +{ + struct elf_prstatus prstatus; + u32 *buf; + + if ((cpu < 0) || (cpu >= NR_CPUS)) + return; + + /* Using ELF notes here is opportunistic. + * I need a well defined structure format + * for the data I pass, and I need tags + * on the data to indicate what information I have + * squirrelled away. ELF notes happen to provide + * all of that that no need to invent something new. + */ + buf = &crash_notes[cpu][0]; + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + elf_core_copy_regs(&prstatus.pr_reg, regs); + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} + +static void crash_get_current_regs(struct pt_regs *regs) +{ + __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx)); + __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx)); + __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx)); + __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi)); + __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi)); + __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp)); + __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax)); + __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp)); + __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss)); + __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs)); + __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds)); + __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes)); + __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags)); + + regs->eip = (unsigned long)current_text_addr(); +} + +/* CPU does not save ss and esp on stack if execution is already + * running in kernel mode at the time of NMI occurrence. This code + * fixes it. + */ +static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) +{ + memcpy(newregs, oldregs, sizeof(*newregs)); + newregs->esp = (unsigned long)&(oldregs->esp); + __asm__ __volatile__("xorl %eax, %eax;"); + __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss)); +} + +/* We may have saved_regs from where the error came from + * or it is NULL if via a direct panic(). + */ +static void crash_save_self(struct pt_regs *saved_regs) +{ + struct pt_regs regs; + int cpu; + + cpu = smp_processor_id(); + if (saved_regs) + crash_setup_regs(®s, saved_regs); + else + crash_get_current_regs(®s); + crash_save_this_cpu(®s, cpu); +} + +#ifdef CONFIG_SMP +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct pt_regs *regs, int cpu) +{ + struct pt_regs fixed_regs; + + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return 1; + local_irq_disable(); + + if (!user_mode(regs)) { + crash_setup_regs(&fixed_regs, regs); + regs = &fixed_regs; + } + crash_save_this_cpu(regs, cpu); + disable_local_APIC(); + atomic_dec(&waiting_for_crash_ipi); + /* Assume hlt works */ + __asm__("hlt"); + for(;;); + + return 1; +} + +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +static void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + +static void nmi_shootdown_cpus(void) +{ + unsigned long msecs; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + set_nmi_callback(crash_nmi_callback); + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + /* Leave the nmi callback set */ + disable_local_APIC(); +} +#else +static void nmi_shootdown_cpus(void) +{ + /* There are no cpus to shootdown */ +} +#endif + +void machine_crash_shutdown(struct pt_regs *regs) +{ + /* This function is only called after the system + * has paniced or is otherwise in a critical state. + * The minimum amount of code to allow a kexec'd kernel + * to run successfully needs to happen here. + * + * In practice this means shooting down the other cpus in + * an SMP system. + */ + /* The kernel is broken so disable interrupts */ + local_irq_disable(); + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = smp_processor_id(); + nmi_shootdown_cpus(); + lapic_shutdown(); +#if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); +#endif + crash_save_self(regs); +} diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c index 6ed7e28f..a3cdf89 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/arch/i386/kernel/dmi_scan.c @@ -1,22 +1,15 @@ #include <linux/types.h> -#include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/acpi.h> -#include <asm/io.h> -#include <linux/pm.h> -#include <asm/system.h> #include <linux/dmi.h> #include <linux/bootmem.h> -struct dmi_header -{ - u8 type; - u8 length; - u16 handle; +struct dmi_header { + u8 type; + u8 length; + u16 handle; }; #undef DMI_DEBUG @@ -29,15 +22,13 @@ struct dmi_header static char * __init dmi_string(struct dmi_header *dm, u8 s) { - u8 *bp=(u8 *)dm; - bp+=dm->length; - if(!s) + u8 *bp = ((u8 *) dm) + dm->length; + + if (!s) return ""; s--; - while(s>0 && *bp) - { - bp+=strlen(bp); - bp++; + while (s > 0 && *bp) { + bp += strlen(bp) + 1; s--; } return bp; @@ -47,16 +38,14 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s) * We have to be cautious here. We have seen BIOSes with DMI pointers * pointing to completely the wrong place for example */ - -static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *)) +static int __init dmi_table(u32 base, int len, int num, + void (*decode)(struct dmi_header *)) { - u8 *buf; - struct dmi_header *dm; - u8 *data; - int i=0; + u8 *buf, *data; + int i = 0; buf = bt_ioremap(base, len); - if(buf==NULL) + if (buf == NULL) return -1; data = buf; @@ -65,36 +54,34 @@ static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dm * Stop when we see all the items the table claimed to have * OR we run off the end of the table (also happens) */ - - while(i<num && data-buf+sizeof(struct dmi_header)<=len) - { - dm=(struct dmi_header *)data; + while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { + struct dmi_header *dm = (struct dmi_header *)data; /* * We want to know the total length (formated area and strings) * before decoding to make sure we won't run off the table in * dmi_decode or dmi_string */ - data+=dm->length; - while(data-buf<len-1 && (data[0] || data[1])) + data += dm->length; + while ((data - buf < len - 1) && (data[0] || data[1])) data++; - if(data-buf<len-1) + if (data - buf < len - 1) decode(dm); - data+=2; + data += 2; i++; } bt_iounmap(buf, len); return 0; } - -inline static int __init dmi_checksum(u8 *buf) +static int __init dmi_checksum(u8 *buf) { - u8 sum=0; + u8 sum = 0; int a; - for(a=0; a<15; a++) - sum+=buf[a]; - return (sum==0); + for (a = 0; a < 15; a++) + sum += buf[a]; + + return sum == 0; } static int __init dmi_iterate(void (*decode)(struct dmi_header *)) @@ -110,28 +97,30 @@ static int __init dmi_iterate(void (*decode)(struct dmi_header *)) p = ioremap(0xF0000, 0x10000); if (p == NULL) return -1; + for (q = p; q < p + 0x10000; q += 16) { memcpy_fromio(buf, q, 15); - if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) - { - u16 num=buf[13]<<8|buf[12]; - u16 len=buf[7]<<8|buf[6]; - u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; + if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { + u16 num = (buf[13] << 8) | buf[12]; + u16 len = (buf[7] << 8) | buf[6]; + u32 base = (buf[11] << 24) | (buf[10] << 16) | + (buf[9] << 8) | buf[8]; /* * DMI version 0.0 means that the real version is taken from * the SMBIOS version, which we don't know at this point. */ - if(buf[14]!=0) + if (buf[14] != 0) printk(KERN_INFO "DMI %d.%d present.\n", - buf[14]>>4, buf[14]&0x0F); + buf[14] >> 4, buf[14] & 0xF); else printk(KERN_INFO "DMI present.\n"); + dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", num, len)); - dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", - base)); - if(dmi_table(base,len, num, decode)==0) + dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base)); + + if (dmi_table(base,len, num, decode) == 0) return 0; } } @@ -143,16 +132,17 @@ static char *dmi_ident[DMI_STRING_MAX]; /* * Save a DMI string */ - static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) { char *d = (char*)dm; char *p = dmi_string(dm, d[string]); - if(p==NULL || *p == 0) + + if (p == NULL || *p == 0) return; if (dmi_ident[slot]) return; - dmi_ident[slot] = alloc_bootmem(strlen(p)+1); + + dmi_ident[slot] = alloc_bootmem(strlen(p) + 1); if(dmi_ident[slot]) strcpy(dmi_ident[slot], p); else @@ -160,281 +150,47 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) } /* - * Ugly compatibility crap. - */ -#define dmi_blacklist dmi_system_id -#define NO_MATCH { DMI_NONE, NULL} -#define MATCH DMI_MATCH - -/* - * Toshiba keyboard likes to repeat keys when they are not repeated. - */ - -static __init int broken_toshiba_keyboard(struct dmi_blacklist *d) -{ - printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, see http://davyd.ucc.asn.au/projects/toshiba/README\n"); - return 0; -} - - -#ifdef CONFIG_ACPI_SLEEP -static __init int reset_videomode_after_s3(struct dmi_blacklist *d) -{ - /* See acpi_wakeup.S */ - extern long acpi_video_flags; - acpi_video_flags |= 2; - return 0; -} -#endif - - -#ifdef CONFIG_ACPI_BOOT -extern int acpi_force; - -static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d) -{ - if (!acpi_force) { - printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); - disable_acpi(); - } else { - printk(KERN_NOTICE - "Warning: DMI blacklist says broken, but acpi forced\n"); - } - return 0; -} - -/* - * Limit ACPI to CPU enumeration for HT - */ -static __init __attribute__((unused)) int force_acpi_ht(struct dmi_blacklist *d) -{ - if (!acpi_force) { - printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); - disable_acpi(); - acpi_ht = 1; - } else { - printk(KERN_NOTICE - "Warning: acpi=force overrules DMI blacklist: acpi=ht\n"); - } - return 0; -} -#endif - -#ifdef CONFIG_ACPI_PCI -static __init int disable_acpi_irq(struct dmi_blacklist *d) -{ - if (!acpi_force) { - printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n", - d->ident); - acpi_noirq_set(); - } - return 0; -} -static __init int disable_acpi_pci(struct dmi_blacklist *d) -{ - if (!acpi_force) { - printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n", - d->ident); - acpi_disable_pci(); - } - return 0; -} -#endif - -/* - * Process the DMI blacklists - */ - - -/* - * This will be expanded over time to force things like the APM - * interrupt mask settings according to the laptop - */ - -static __initdata struct dmi_blacklist dmi_blacklist[]={ - - { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */ - MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), - NO_MATCH, NO_MATCH, NO_MATCH - } }, -#ifdef CONFIG_ACPI_SLEEP - { reset_videomode_after_s3, "Toshiba Satellite 4030cdt", { /* Reset video mode after returning from ACPI S3 sleep */ - MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), - NO_MATCH, NO_MATCH, NO_MATCH - } }, -#endif - -#ifdef CONFIG_ACPI_BOOT - /* - * If your system is blacklisted here, but you find that acpi=force - * works for you, please contact acpi-devel@sourceforge.net - */ - - /* - * Boxes that need ACPI disabled - */ - - { dmi_disable_acpi, "IBM Thinkpad", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "2629H1G"), - NO_MATCH, NO_MATCH }}, - - /* - * Boxes that need acpi=ht - */ - - { force_acpi_ht, "FSC Primergy T850", { - MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "DELL GX240", { - MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"), - MATCH(DMI_BOARD_NAME, "OptiPlex GX240"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "HP VISUALIZE NT Workstation", { - MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), - MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "Compaq Workstation W8000", { - MATCH(DMI_SYS_VENDOR, "Compaq"), - MATCH(DMI_PRODUCT_NAME, "Workstation W8000"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "ASUS P4B266", { - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - MATCH(DMI_BOARD_NAME, "P4B266"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "ASUS P2B-DS", { - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - MATCH(DMI_BOARD_NAME, "P2B-DS"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "ASUS CUR-DLS", { - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - MATCH(DMI_BOARD_NAME, "CUR-DLS"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "ABIT i440BX-W83977", { - MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"), - MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "IBM Bladecenter", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "IBM eServer xSeries 360", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "eServer xSeries 360"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "IBM eserver xSeries 330", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_BOARD_NAME, "eserver xSeries 330"), - NO_MATCH, NO_MATCH }}, - - { force_acpi_ht, "IBM eserver xSeries 440", { - MATCH(DMI_BOARD_VENDOR, "IBM"), - MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"), - NO_MATCH, NO_MATCH }}, - -#endif // CONFIG_ACPI_BOOT - -#ifdef CONFIG_ACPI_PCI - /* - * Boxes that need ACPI PCI IRQ routing disabled - */ - - { disable_acpi_irq, "ASUS A7V", { - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"), - MATCH(DMI_BOARD_NAME, "<A7V>"), - /* newer BIOS, Revision 1011, does work */ - MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"), - NO_MATCH }}, - - /* - * Boxes that need ACPI PCI IRQ routing and PCI scan disabled - */ - { disable_acpi_pci, "ASUS PR-DLS", { /* _BBN 0 bug */ - MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - MATCH(DMI_BOARD_NAME, "PR-DLS"), - MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"), - MATCH(DMI_BIOS_DATE, "03/21/2003") }}, - - { disable_acpi_pci, "Acer TravelMate 36x Laptop", { - MATCH(DMI_SYS_VENDOR, "Acer"), - MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), - NO_MATCH, NO_MATCH - } }, - -#endif - - { NULL, } -}; - -/* * Process a DMI table entry. Right now all we care about are the BIOS * and machine entries. For 2.5 we should pull the smbus controller info * out of here. */ - static void __init dmi_decode(struct dmi_header *dm) { -#ifdef DMI_DEBUG - u8 *data = (u8 *)dm; -#endif + u8 *data __attribute__((__unused__)) = (u8 *)dm; - switch(dm->type) - { - case 0: - dmi_printk(("BIOS Vendor: %s\n", - dmi_string(dm, data[4]))); - dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); - dmi_printk(("BIOS Version: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_BIOS_VERSION, 5); - dmi_printk(("BIOS Release: %s\n", - dmi_string(dm, data[8]))); - dmi_save_ident(dm, DMI_BIOS_DATE, 8); - break; - case 1: - dmi_printk(("System Vendor: %s\n", - dmi_string(dm, data[4]))); - dmi_save_ident(dm, DMI_SYS_VENDOR, 4); - dmi_printk(("Product Name: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); - dmi_printk(("Version: %s\n", - dmi_string(dm, data[6]))); - dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); - dmi_printk(("Serial Number: %s\n", - dmi_string(dm, data[7]))); - break; - case 2: - dmi_printk(("Board Vendor: %s\n", - dmi_string(dm, data[4]))); - dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); - dmi_printk(("Board Name: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_BOARD_NAME, 5); - dmi_printk(("Board Version: %s\n", - dmi_string(dm, data[6]))); - dmi_save_ident(dm, DMI_BOARD_VERSION, 6); - break; + switch(dm->type) { + case 0: + dmi_printk(("BIOS Vendor: %s\n", dmi_string(dm, data[4]))); + dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); + dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BIOS_VERSION, 5); + dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8]))); + dmi_save_ident(dm, DMI_BIOS_DATE, 8); + break; + case 1: + dmi_printk(("System Vendor: %s\n", dmi_string(dm, data[4]))); + dmi_save_ident(dm, DMI_SYS_VENDOR, 4); + dmi_printk(("Product Name: %s\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); + dmi_printk(("Version: %s\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); + dmi_printk(("Serial Number: %s\n", dmi_string(dm, data[7]))); + dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); + break; + case 2: + dmi_printk(("Board Vendor: %s\n", dmi_string(dm, data[4]))); + dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); + dmi_printk(("Board Name: %s\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BOARD_NAME, 5); + dmi_printk(("Board Version: %s\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_BOARD_VERSION, 6); + break; } } void __init dmi_scan_machine(void) { - int err = dmi_iterate(dmi_decode); - if(err == 0) - dmi_check_system(dmi_blacklist); - else + if (dmi_iterate(dmi_decode)) printk(KERN_INFO "DMI not present.\n"); } @@ -470,7 +226,6 @@ fail: d++; return count; } - EXPORT_SYMBOL(dmi_check_system); /** @@ -480,8 +235,8 @@ EXPORT_SYMBOL(dmi_check_system); * Returns one DMI data value, can be used to perform * complex DMI data checks. */ -char * dmi_get_system_info(int field) +char *dmi_get_system_info(int field) { return dmi_ident[field]; } - +EXPORT_SYMBOL(dmi_get_system_info); diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c index f732f42..385883e 100644 --- a/arch/i386/kernel/efi.c +++ b/arch/i386/kernel/efi.c @@ -30,6 +30,7 @@ #include <linux/ioport.h> #include <linux/module.h> #include <linux/efi.h> +#include <linux/kexec.h> #include <asm/setup.h> #include <asm/io.h> @@ -598,6 +599,9 @@ efi_initialize_iomem_resources(struct resource *code_resource, if (md->type == EFI_CONVENTIONAL_MEMORY) { request_resource(res, code_resource); request_resource(res, data_resource); +#ifdef CONFIG_KEXEC + request_resource(res, &crashk_res); +#endif } } } diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index e966fc8c..4477bb1 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -299,7 +299,6 @@ is386: movl $2,%ecx # set MP movl %eax,%cr0 call check_x87 - incb ready lgdt cpu_gdt_descr lidt idt_descr ljmp $(__KERNEL_CS),$1f @@ -316,8 +315,9 @@ is386: movl $2,%ecx # set MP lldt %ax cld # gcc2 wants the direction flag cleared at all times #ifdef CONFIG_SMP - movb ready, %cl - cmpb $1,%cl + movb ready, %cl + movb $1, ready + cmpb $0,%cl je 1f # the first CPU calls start_kernel # all other CPUs call initialize_secondary call initialize_secondary diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index 2c4813b..178f4e9 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -268,10 +268,22 @@ static int i8259A_suspend(struct sys_device *dev, pm_message_t state) return 0; } +static int i8259A_shutdown(struct sys_device *dev) +{ + /* Put the i8259A into a quiescent state that + * the kernel initialization code can get it + * out of. + */ + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-1 */ + return 0; +} + static struct sysdev_class i8259_sysdev_class = { set_kset_name("i8259"), .suspend = i8259A_suspend, .resume = i8259A_resume, + .shutdown = i8259A_shutdown, }; static struct sys_device device_i8259A = { diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 08540bc..35eb8e2 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -573,12 +573,14 @@ static int balanced_irq(void *unused) for ( ; ; ) { set_current_state(TASK_INTERRUPTIBLE); time_remaining = schedule_timeout(time_remaining); - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (time_after(jiffies, prev_balance_time+balanced_irq_interval)) { + preempt_disable(); do_irq_balance(); prev_balance_time = jiffies; time_remaining = balanced_irq_interval; + preempt_enable(); } } return 0; @@ -630,10 +632,8 @@ static int __init balanced_irq_init(void) printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); failed: for (i = 0; i < NR_CPUS; i++) { - if(irq_cpu_data[i].irq_delta) - kfree(irq_cpu_data[i].irq_delta); - if(irq_cpu_data[i].last_irq) - kfree(irq_cpu_data[i].last_irq); + kfree(irq_cpu_data[i].irq_delta); + kfree(irq_cpu_data[i].last_irq); } return 0; } @@ -1634,12 +1634,43 @@ static void __init enable_IO_APIC(void) */ void disable_IO_APIC(void) { + int pin; /* * Clear the IO-APIC before rebooting: */ clear_IO_APIC(); - disconnect_bsp_APIC(); + /* + * If the i82559 is routed through an IOAPIC + * Put that IOAPIC in virtual wire mode + * so legacy interrups can be delivered. + */ + pin = find_isa_irq_pin(0, mp_ExtINT); + if (pin != -1) { + struct IO_APIC_route_entry entry; + unsigned long flags; + + memset(&entry, 0, sizeof(entry)); + entry.mask = 0; /* Enabled */ + entry.trigger = 0; /* Edge */ + entry.irr = 0; + entry.polarity = 0; /* High */ + entry.delivery_status = 0; + entry.dest_mode = 0; /* Physical */ + entry.delivery_mode = 7; /* ExtInt */ + entry.vector = 0; + entry.dest.physical.physical_dest = 0; + + + /* + * Add it to the IO-APIC irq-routing table: + */ + spin_lock_irqsave(&ioapic_lock, flags); + io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + disconnect_bsp_APIC(pin != -1); } /* diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 73945a3..ce66dcc 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -15,6 +15,9 @@ #include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/notifier.h> +#include <linux/cpu.h> +#include <linux/delay.h> DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); @@ -153,6 +156,11 @@ void irq_ctx_init(int cpu) cpu,hardirq_ctx[cpu],softirq_ctx[cpu]); } +void irq_ctx_exit(int cpu) +{ + hardirq_ctx[cpu] = NULL; +} + extern asmlinkage void __do_softirq(void); asmlinkage void do_softirq(void) @@ -210,9 +218,8 @@ int show_interrupts(struct seq_file *p, void *v) if (i == 0) { seq_printf(p, " "); - for (j=0; j<NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); + for_each_cpu(j) + seq_printf(p, "CPU%d ",j); seq_putc(p, '\n'); } @@ -225,9 +232,8 @@ int show_interrupts(struct seq_file *p, void *v) #ifndef CONFIG_SMP seq_printf(p, "%10u ", kstat_irqs(i)); #else - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); + for_each_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif seq_printf(p, " %14s", irq_desc[i].handler->typename); seq_printf(p, " %s", action->name); @@ -240,16 +246,14 @@ skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); } else if (i == NR_IRQS) { seq_printf(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", nmi_count(j)); + for_each_cpu(j) + seq_printf(p, "%10u ", nmi_count(j)); seq_putc(p, '\n'); #ifdef CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", - per_cpu(irq_stat,j).apic_timer_irqs); + for_each_cpu(j) + seq_printf(p, "%10u ", + per_cpu(irq_stat,j).apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -259,3 +263,45 @@ skip: } return 0; } + +#ifdef CONFIG_HOTPLUG_CPU +#include <mach_apic.h> + +void fixup_irqs(cpumask_t map) +{ + unsigned int irq; + static int warned; + + for (irq = 0; irq < NR_IRQS; irq++) { + cpumask_t mask; + if (irq == 2) + continue; + + cpus_and(mask, irq_affinity[irq], map); + if (any_online_cpu(mask) == NR_CPUS) { + printk("Breaking affinity for irq %i\n", irq); + mask = map; + } + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + else if (irq_desc[irq].action && !(warned++)) + printk("Cannot set affinity for irq %i\n", irq); + } + +#if 0 + barrier(); + /* Ingo Molnar says: "after the IO-APIC masks have been redirected + [note the nop - the interrupt-enable boundary on x86 is two + instructions from sti] - to flush out pending hardirqs and + IPIs. After this point nothing is supposed to reach this CPU." */ + __asm__ __volatile__("sti; nop; cli"); + barrier(); +#else + /* That doesn't seem sufficient. Give it 1ms. */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); +#endif +} +#endif + diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c new file mode 100644 index 0000000..52ed18d --- /dev/null +++ b/arch/i386/kernel/machine_kexec.c @@ -0,0 +1,226 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/mm.h> +#include <linux/kexec.h> +#include <linux/delay.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/apic.h> +#include <asm/cpufeature.h> + +static inline unsigned long read_cr3(void) +{ + unsigned long cr3; + asm volatile("movl %%cr3,%0": "=r"(cr3)); + return cr3; +} + +#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) + +#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define L2_ATTR (_PAGE_PRESENT) + +#define LEVEL0_SIZE (1UL << 12UL) + +#ifndef CONFIG_X86_PAE +#define LEVEL1_SIZE (1UL << 22UL) +static u32 pgtable_level1[1024] PAGE_ALIGNED; + +static void identity_map_page(unsigned long address) +{ + unsigned long level1_index, level2_index; + u32 *pgtable_level2; + + /* Find the current page table */ + pgtable_level2 = __va(read_cr3()); + + /* Find the indexes of the physical address to identity map */ + level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; + level2_index = address / LEVEL1_SIZE; + + /* Identity map the page table entry */ + pgtable_level1[level1_index] = address | L0_ATTR; + pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; + + /* Flush the tlb so the new mapping takes effect. + * Global tlb entries are not flushed but that is not an issue. + */ + load_cr3(pgtable_level2); +} + +#else +#define LEVEL1_SIZE (1UL << 21UL) +#define LEVEL2_SIZE (1UL << 30UL) +static u64 pgtable_level1[512] PAGE_ALIGNED; +static u64 pgtable_level2[512] PAGE_ALIGNED; + +static void identity_map_page(unsigned long address) +{ + unsigned long level1_index, level2_index, level3_index; + u64 *pgtable_level3; + + /* Find the current page table */ + pgtable_level3 = __va(read_cr3()); + + /* Find the indexes of the physical address to identity map */ + level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; + level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE; + level3_index = address / LEVEL2_SIZE; + + /* Identity map the page table entry */ + pgtable_level1[level1_index] = address | L0_ATTR; + pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; + set_64bit(&pgtable_level3[level3_index], + __pa(pgtable_level2) | L2_ATTR); + + /* Flush the tlb so the new mapping takes effect. + * Global tlb entries are not flushed but that is not an issue. + */ + load_cr3(pgtable_level3); +} +#endif + + +static void set_idt(void *newidt, __u16 limit) +{ + unsigned char curidt[6]; + + /* ia32 supports unaliged loads & stores */ + (*(__u16 *)(curidt)) = limit; + (*(__u32 *)(curidt +2)) = (unsigned long)(newidt); + + __asm__ __volatile__ ( + "lidt %0\n" + : "=m" (curidt) + ); +}; + + +static void set_gdt(void *newgdt, __u16 limit) +{ + unsigned char curgdt[6]; + + /* ia32 supports unaligned loads & stores */ + (*(__u16 *)(curgdt)) = limit; + (*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt); + + __asm__ __volatile__ ( + "lgdt %0\n" + : "=m" (curgdt) + ); +}; + +static void load_segments(void) +{ +#define __STR(X) #X +#define STR(X) __STR(X) + + __asm__ __volatile__ ( + "\tljmp $"STR(__KERNEL_CS)",$1f\n" + "\t1:\n" + "\tmovl $"STR(__KERNEL_DS)",%eax\n" + "\tmovl %eax,%ds\n" + "\tmovl %eax,%es\n" + "\tmovl %eax,%fs\n" + "\tmovl %eax,%gs\n" + "\tmovl %eax,%ss\n" + ); +#undef STR +#undef __STR +} + +typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long reboot_code_buffer, + unsigned long start_address, + unsigned int has_pae) ATTRIB_NORET; + +const extern unsigned char relocate_new_kernel[]; +extern void relocate_new_kernel_end(void); +const extern unsigned int relocate_new_kernel_size; + +/* + * A architecture hook called to validate the + * proposed image and prepare the control pages + * as needed. The pages for KEXEC_CONTROL_CODE_SIZE + * have been allocated, but the segments have yet + * been copied into the kernel. + * + * Do what every setup is needed on image and the + * reboot code buffer to allow us to avoid allocations + * later. + * + * Currently nothing. + */ +int machine_kexec_prepare(struct kimage *image) +{ + return 0; +} + +/* + * Undo anything leftover by machine_kexec_prepare + * when an image is freed. + */ +void machine_kexec_cleanup(struct kimage *image) +{ +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) +{ + unsigned long page_list; + unsigned long reboot_code_buffer; + + relocate_new_kernel_t rnk; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + /* Compute some offsets */ + reboot_code_buffer = page_to_pfn(image->control_code_page) + << PAGE_SHIFT; + page_list = image->head; + + /* Set up an identity mapping for the reboot_code_buffer */ + identity_map_page(reboot_code_buffer); + + /* copy it out */ + memcpy((void *)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); + + /* The segment registers are funny things, they are + * automatically loaded from a table, in memory wherever you + * set them to a specific selector, but this table is never + * accessed again you set the segment to a different selector. + * + * The more common model is are caches where the behide + * the scenes work is done, but is also dropped at arbitrary + * times. + * + * I take advantage of this here by force loading the + * segments, before I zap the gdt with an invalid value. + */ + load_segments(); + /* The gdt & idt are now invalid. + * If you want to load them you must set up your own idt & gdt. + */ + set_gdt(phys_to_virt(0),0); + set_idt(phys_to_virt(0),0); + + /* now call it */ + rnk = (relocate_new_kernel_t) reboot_code_buffer; + (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); +} diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 383a116..af917f6 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -67,7 +67,6 @@ unsigned long mp_lapic_addr; /* Processor that is doing the boot up */ unsigned int boot_cpu_physical_apicid = -1U; -unsigned int boot_cpu_logical_apicid = -1U; /* Internal processor count */ static unsigned int __initdata num_processors; @@ -180,7 +179,6 @@ static void __init MP_processor_info (struct mpc_config_processor *m) if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_physical_apicid = m->mpc_apicid; - boot_cpu_logical_apicid = apicid; } if (num_processors >= NR_CPUS) { diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index aea2ce1..5f8cfa6 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -13,6 +13,7 @@ #include <stdarg.h> +#include <linux/cpu.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/fs.h> @@ -55,6 +56,9 @@ #include <linux/irq.h> #include <linux/err.h> +#include <asm/tlbflush.h> +#include <asm/cpu.h> + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); static int hlt_counter; @@ -143,14 +147,42 @@ static void poll_idle (void) } } +#ifdef CONFIG_HOTPLUG_CPU +#include <asm/nmi.h> +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void play_dead(void) +{ + /* This must be done before dead CPU ack */ + cpu_exit_clear(); + wbinvd(); + mb(); + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + /* + * With physical CPU hotplug, we should halt the cpu + */ + local_irq_disable(); + while (1) + __asm__ __volatile__("hlt":::"memory"); +} +#else +static inline void play_dead(void) +{ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + /* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a * low exit latency (ie sit in a loop waiting for * somebody to say that they'd like to reschedule) */ -void cpu_idle (void) +void cpu_idle(void) { + int cpu = raw_smp_processor_id(); + /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { @@ -165,6 +197,9 @@ void cpu_idle (void) if (!idle) idle = default_idle; + if (cpu_is_offline(cpu)) + play_dead(); + __get_cpu_var(irq_stat).idle_timestamp = jiffies; idle(); } @@ -223,7 +258,7 @@ static void mwait_idle(void) } } -void __init select_idle_routine(const struct cpuinfo_x86 *c) +void __devinit select_idle_routine(const struct cpuinfo_x86 *c) { if (cpu_has(c, X86_FEATURE_MWAIT)) { printk("monitor/mwait feature present.\n"); diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index db91220..b3e5848 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -26,7 +26,6 @@ static int reboot_mode; static int reboot_thru_bios; #ifdef CONFIG_SMP -int reboot_smp = 0; static int reboot_cpu = -1; /* shamelessly grabbed from lib/vsprintf.c for readability */ #define is_digit(c) ((c) >= '0' && (c) <= '9') @@ -49,7 +48,6 @@ static int __init reboot_setup(char *str) break; #ifdef CONFIG_SMP case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ - reboot_smp = 1; if (is_digit(*(str+1))) { reboot_cpu = (int) (*(str+1) - '0'); if (is_digit(*(str+2))) @@ -88,33 +86,9 @@ static int __init set_bios_reboot(struct dmi_system_id *d) return 0; } -/* - * Some machines require the "reboot=s" commandline option, this quirk makes that automatic. - */ -static int __init set_smp_reboot(struct dmi_system_id *d) -{ -#ifdef CONFIG_SMP - if (!reboot_smp) { - reboot_smp = 1; - printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident); - } -#endif - return 0; -} - -/* - * Some machines require the "reboot=b,s" commandline option, this quirk makes that automatic. - */ -static int __init set_smp_bios_reboot(struct dmi_system_id *d) -{ - set_smp_reboot(d); - set_bios_reboot(d); - return 0; -} - static struct dmi_system_id __initdata reboot_dmi_table[] = { { /* Handle problems with rebooting on Dell 1300's */ - .callback = set_smp_bios_reboot, + .callback = set_bios_reboot, .ident = "Dell PowerEdge 1300", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), @@ -301,41 +275,32 @@ void machine_real_restart(unsigned char *code, int length) EXPORT_SYMBOL(machine_real_restart); #endif -void machine_restart(char * __unused) +void machine_shutdown(void) { #ifdef CONFIG_SMP - int cpuid; - - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - if (reboot_smp) { - - /* check to see if reboot_cpu is valid - if its not, default to the BSP */ - if ((reboot_cpu == -1) || - (reboot_cpu > (NR_CPUS -1)) || - !physid_isset(cpuid, phys_cpu_present_map)) - reboot_cpu = boot_cpu_physical_apicid; - - reboot_smp = 0; /* use this as a flag to only go through this once*/ - /* re-run this function on the other CPUs - it will fall though this section since we have - cleared reboot_smp, and do the reboot if it is the - correct CPU, otherwise it halts. */ - if (reboot_cpu != cpuid) - smp_call_function((void *)machine_restart , NULL, 1, 0); + int reboot_cpu_id; + + /* The boot cpu is always logical cpu 0 */ + reboot_cpu_id = 0; + + /* See if there has been given a command line override */ + if ((reboot_cpu_id != -1) && (reboot_cpu < NR_CPUS) && + cpu_isset(reboot_cpu, cpu_online_map)) { + reboot_cpu_id = reboot_cpu; } - /* if reboot_cpu is still -1, then we want a tradional reboot, - and if we are not running on the reboot_cpu,, halt */ - if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) { - for (;;) - __asm__ __volatile__ ("hlt"); + /* Make certain the cpu I'm rebooting on is online */ + if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { + reboot_cpu_id = smp_processor_id(); } - /* - * Stop all CPUs and turn off local APICs and the IO-APIC, so - * other OSs see a clean IRQ state. + + /* Make certain I only run on the appropriate processor */ + set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); + + /* O.K. Now that I'm on the appropriate processor, stop + * all of the others, and disable their local APICs. */ + smp_send_stop(); #endif /* CONFIG_SMP */ @@ -344,6 +309,11 @@ void machine_restart(char * __unused) #ifdef CONFIG_X86_IO_APIC disable_IO_APIC(); #endif +} + +void machine_restart(char * __unused) +{ + machine_shutdown(); if (!reboot_thru_bios) { if (efi_enabled) { diff --git a/arch/i386/kernel/relocate_kernel.S b/arch/i386/kernel/relocate_kernel.S new file mode 100644 index 0000000..d312616 --- /dev/null +++ b/arch/i386/kernel/relocate_kernel.S @@ -0,0 +1,120 @@ +/* + * relocate_kernel.S - put the kernel image in place to boot + * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com> + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/linkage.h> + + /* + * Must be relocatable PIC code callable as a C function, that once + * it starts can not use the previous processes stack. + */ + .globl relocate_new_kernel +relocate_new_kernel: + /* read the arguments and say goodbye to the stack */ + movl 4(%esp), %ebx /* page_list */ + movl 8(%esp), %ebp /* reboot_code_buffer */ + movl 12(%esp), %edx /* start address */ + movl 16(%esp), %ecx /* cpu_has_pae */ + + /* zero out flags, and disable interrupts */ + pushl $0 + popfl + + /* set a new stack at the bottom of our page... */ + lea 4096(%ebp), %esp + + /* store the parameters back on the stack */ + pushl %edx /* store the start address */ + + /* Set cr0 to a known state: + * 31 0 == Paging disabled + * 18 0 == Alignment check disabled + * 16 0 == Write protect disabled + * 3 0 == No task switch + * 2 0 == Don't do FP software emulation. + * 0 1 == Proctected mode enabled + */ + movl %cr0, %eax + andl $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax + orl $(1<<0), %eax + movl %eax, %cr0 + + /* clear cr4 if applicable */ + testl %ecx, %ecx + jz 1f + /* Set cr4 to a known state: + * Setting everything to zero seems safe. + */ + movl %cr4, %eax + andl $0, %eax + movl %eax, %cr4 + + jmp 1f +1: + + /* Flush the TLB (needed?) */ + xorl %eax, %eax + movl %eax, %cr3 + + /* Do the copies */ + movl %ebx, %ecx + jmp 1f + +0: /* top, read another word from the indirection page */ + movl (%ebx), %ecx + addl $4, %ebx +1: + testl $0x1, %ecx /* is it a destination page */ + jz 2f + movl %ecx, %edi + andl $0xfffff000, %edi + jmp 0b +2: + testl $0x2, %ecx /* is it an indirection page */ + jz 2f + movl %ecx, %ebx + andl $0xfffff000, %ebx + jmp 0b +2: + testl $0x4, %ecx /* is it the done indicator */ + jz 2f + jmp 3f +2: + testl $0x8, %ecx /* is it the source indicator */ + jz 0b /* Ignore it otherwise */ + movl %ecx, %esi /* For every source page do a copy */ + andl $0xfffff000, %esi + + movl $1024, %ecx + rep ; movsl + jmp 0b + +3: + + /* To be certain of avoiding problems with self-modifying code + * I need to execute a serializing instruction here. + * So I flush the TLB, it's handy, and not processor dependent. + */ + xorl %eax, %eax + movl %eax, %cr3 + + /* set all of the registers to known values */ + /* leave %esp alone */ + + xorl %eax, %eax + xorl %ebx, %ebx + xorl %ecx, %ecx + xorl %edx, %edx + xorl %esi, %esi + xorl %edi, %edi + xorl %ebp, %ebp + ret +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 30406fd..7306353 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -43,7 +43,12 @@ #include <linux/init.h> #include <linux/edd.h> #include <linux/nodemask.h> +#include <linux/kexec.h> +#include <linux/crash_dump.h> + #include <video/edid.h> + +#include <asm/apic.h> #include <asm/e820.h> #include <asm/mpspec.h> #include <asm/setup.h> @@ -55,12 +60,15 @@ #include "setup_arch_pre.h" #include <bios_ebda.h> +/* Forward Declaration. */ +void __init find_max_pfn(void); + /* This value is set up by the early boot code to point to the value immediately after the boot time page tables. It contains a *physical* address, and must not be in the .bss segment! */ unsigned long init_pg_tables_end __initdata = ~0UL; -int disable_pse __initdata = 0; +int disable_pse __devinitdata = 0; /* * Machine setup.. @@ -732,6 +740,15 @@ static void __init parse_cmdline_early (char ** cmdline_p) if (to != command_line) to--; if (!memcmp(from+7, "exactmap", 8)) { +#ifdef CONFIG_CRASH_DUMP + /* If we are doing a crash dump, we + * still need to know the real mem + * size before original memory map is + * reset. + */ + find_max_pfn(); + saved_max_pfn = max_pfn; +#endif from += 8+7; e820.nr_map = 0; userdef = 1; @@ -835,6 +852,44 @@ static void __init parse_cmdline_early (char ** cmdline_p) #endif /* CONFIG_X86_LOCAL_APIC */ #endif /* CONFIG_ACPI_BOOT */ +#ifdef CONFIG_X86_LOCAL_APIC + /* enable local APIC */ + else if (!memcmp(from, "lapic", 5)) + lapic_enable(); + + /* disable local APIC */ + else if (!memcmp(from, "nolapic", 6)) + lapic_disable(); +#endif /* CONFIG_X86_LOCAL_APIC */ + +#ifdef CONFIG_KEXEC + /* crashkernel=size@addr specifies the location to reserve for + * a crash kernel. By reserving this memory we guarantee + * that linux never set's it up as a DMA target. + * Useful for holding code to do something appropriate + * after a kernel panic. + */ + else if (!memcmp(from, "crashkernel=", 12)) { + unsigned long size, base; + size = memparse(from+12, &from); + if (*from == '@') { + base = memparse(from+1, &from); + /* FIXME: Do I want a sanity check + * to validate the memory range? + */ + crashk_res.start = base; + crashk_res.end = base + size - 1; + } + } +#endif +#ifdef CONFIG_CRASH_DUMP + /* elfcorehdr= specifies the location of elf core header + * stored by the crashed kernel. + */ + else if (!memcmp(from, "elfcorehdr=", 11)) + elfcorehdr_addr = memparse(from+11, &from); +#endif + /* * highmem=size forces highmem to be exactly 'size' bytes. * This works even on boxes that have no highmem otherwise. @@ -1113,8 +1168,8 @@ void __init setup_bootmem_allocator(void) * the (very unlikely) case of us accidentally initializing the * bootmem allocator with an invalid RAM area. */ - reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(min_low_pfn) + - bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY)); + reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) + + bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START)); /* * reserve physical page 0 - it's a special BIOS page on many boxes, @@ -1170,6 +1225,11 @@ void __init setup_bootmem_allocator(void) } } #endif +#ifdef CONFIG_KEXEC + if (crashk_res.start != crashk_res.end) + reserve_bootmem(crashk_res.start, + crashk_res.end - crashk_res.start + 1); +#endif } /* @@ -1223,6 +1283,9 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat */ request_resource(res, code_resource); request_resource(res, data_resource); +#ifdef CONFIG_KEXEC + request_resource(res, &crashk_res); +#endif } } } diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index b9b8f4e..89ef7ad 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -608,10 +608,8 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } if (!oldset) oldset = ¤t->blocked; diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 68be7d0c..cec4bde 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -19,6 +19,7 @@ #include <linux/mc146818rtc.h> #include <linux/cache.h> #include <linux/interrupt.h> +#include <linux/cpu.h> #include <linux/module.h> #include <asm/mtrr.h> @@ -164,7 +165,7 @@ void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) unsigned long flags; local_irq_save(flags); - + WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); /* * Wait for idle. */ @@ -346,21 +347,21 @@ out: static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, unsigned long va) { - cpumask_t tmp; /* * A couple of (to be removed) sanity checks: * - * - we do not send IPIs to not-yet booted CPUs. * - current CPU must not be in mask * - mask must exist :) */ BUG_ON(cpus_empty(cpumask)); - - cpus_and(tmp, cpumask, cpu_online_map); - BUG_ON(!cpus_equal(cpumask, tmp)); BUG_ON(cpu_isset(smp_processor_id(), cpumask)); BUG_ON(!mm); + /* If a CPU which we ran on has gone down, OK. */ + cpus_and(cpumask, cpumask, cpu_online_map); + if (cpus_empty(cpumask)) + return; + /* * i'm not happy about this global shared spinlock in the * MM hot path, but we'll see how contended it is. @@ -476,6 +477,7 @@ void flush_tlb_all(void) */ void smp_send_reschedule(int cpu) { + WARN_ON(cpu_is_offline(cpu)); send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); } @@ -493,6 +495,16 @@ struct call_data_struct { int wait; }; +void lock_ipi_call_lock(void) +{ + spin_lock_irq(&call_lock); +} + +void unlock_ipi_call_lock(void) +{ + spin_unlock_irq(&call_lock); +} + static struct call_data_struct * call_data; /* @@ -516,10 +528,15 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, */ { struct call_data_struct data; - int cpus = num_online_cpus()-1; + int cpus; - if (!cpus) + /* Holding any lock stops cpus from going down. */ + spin_lock(&call_lock); + cpus = num_online_cpus() - 1; + if (!cpus) { + spin_unlock(&call_lock); return 0; + } /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); @@ -531,7 +548,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); call_data = &data; mb(); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index c20d96d..d66bf48 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -44,6 +44,9 @@ #include <linux/smp_lock.h> #include <linux/irq.h> #include <linux/bootmem.h> +#include <linux/notifier.h> +#include <linux/cpu.h> +#include <linux/percpu.h> #include <linux/delay.h> #include <linux/mc146818rtc.h> @@ -56,18 +59,28 @@ #include <smpboot_hooks.h> /* Set if we find a B stepping CPU */ -static int __initdata smp_b_stepping; +static int __devinitdata smp_b_stepping; /* Number of siblings per CPU package */ int smp_num_siblings = 1; #ifdef CONFIG_X86_HT EXPORT_SYMBOL(smp_num_siblings); #endif -int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ + +/* Package ID of each logical CPU */ +int phys_proc_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID}; EXPORT_SYMBOL(phys_proc_id); -int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */ + +/* Core ID of each logical CPU */ +int cpu_core_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID}; EXPORT_SYMBOL(cpu_core_id); +cpumask_t cpu_sibling_map[NR_CPUS]; +EXPORT_SYMBOL(cpu_sibling_map); + +cpumask_t cpu_core_map[NR_CPUS]; +EXPORT_SYMBOL(cpu_core_map); + /* bitmap of online cpus */ cpumask_t cpu_online_map; EXPORT_SYMBOL(cpu_online_map); @@ -77,6 +90,12 @@ cpumask_t cpu_callout_map; EXPORT_SYMBOL(cpu_callout_map); static cpumask_t smp_commenced_mask; +/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there + * is no way to resync one AP against BP. TBD: for prescott and above, we + * should use IA64's algorithm + */ +static int __devinitdata tsc_sync_disabled; + /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; EXPORT_SYMBOL(cpu_data); @@ -96,13 +115,16 @@ static int trampoline_exec; static void map_cpu_to_logical_apicid(void); +/* State of each CPU. */ +DEFINE_PER_CPU(int, cpu_state) = { 0 }; + /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller * has made sure it's suitably aligned. */ -static unsigned long __init setup_trampoline(void) +static unsigned long __devinit setup_trampoline(void) { memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); return virt_to_phys(trampoline_base); @@ -132,7 +154,7 @@ void __init smp_alloc_memory(void) * a given CPU */ -static void __init smp_store_cpu_info(int id) +static void __devinit smp_store_cpu_info(int id) { struct cpuinfo_x86 *c = cpu_data + id; @@ -326,7 +348,7 @@ extern void calibrate_delay(void); static atomic_t init_deasserted; -static void __init smp_callin(void) +static void __devinit smp_callin(void) { int cpuid, phys_id; unsigned long timeout; @@ -411,16 +433,48 @@ static void __init smp_callin(void) /* * Synchronize the TSC with the BP */ - if (cpu_has_tsc && cpu_khz) + if (cpu_has_tsc && cpu_khz && !tsc_sync_disabled) synchronize_tsc_ap(); } static int cpucount; +static inline void +set_cpu_sibling_map(int cpu) +{ + int i; + + if (smp_num_siblings > 1) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_isset(i, cpu_callout_map)) + continue; + if (cpu_core_id[cpu] == cpu_core_id[i]) { + cpu_set(i, cpu_sibling_map[cpu]); + cpu_set(cpu, cpu_sibling_map[i]); + } + } + } else { + cpu_set(cpu, cpu_sibling_map[cpu]); + } + + if (current_cpu_data.x86_num_cores > 1) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_isset(i, cpu_callout_map)) + continue; + if (phys_proc_id[cpu] == phys_proc_id[i]) { + cpu_set(i, cpu_core_map[cpu]); + cpu_set(cpu, cpu_core_map[i]); + } + } + } else { + cpu_core_map[cpu] = cpu_sibling_map[cpu]; + } +} + /* * Activate a secondary processor. */ -static void __init start_secondary(void *unused) +static void __devinit start_secondary(void *unused) { /* * Dont put anything before smp_callin(), SMP @@ -443,7 +497,23 @@ static void __init start_secondary(void *unused) * the local TLBs too. */ local_flush_tlb(); + + /* This must be done before setting cpu_online_map */ + set_cpu_sibling_map(raw_smp_processor_id()); + wmb(); + + /* + * We need to hold call_lock, so there is no inconsistency + * between the time smp_call_function() determines number of + * IPI receipients, and the time when the determination is made + * for which cpus receive the IPI. Holding this + * lock helps us to not include this cpu in a currently in progress + * smp_call_function(). + */ + lock_ipi_call_lock(); cpu_set(smp_processor_id(), cpu_online_map); + unlock_ipi_call_lock(); + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; /* We can take interrupts now: we're officially "up". */ local_irq_enable(); @@ -458,7 +528,7 @@ static void __init start_secondary(void *unused) * from the task structure * This function must not return. */ -void __init initialize_secondary(void) +void __devinit initialize_secondary(void) { /* * We don't actually need to load the full TSS, @@ -572,7 +642,7 @@ static inline void __inquire_remote_apic(int apicid) * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this * won't ... remember to clear down the APIC, etc later. */ -static int __init +static int __devinit wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) { unsigned long send_status = 0, accept_status = 0; @@ -618,7 +688,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) #endif /* WAKE_SECONDARY_VIA_NMI */ #ifdef WAKE_SECONDARY_VIA_INIT -static int __init +static int __devinit wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) { unsigned long send_status = 0, accept_status = 0; @@ -753,8 +823,43 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) #endif /* WAKE_SECONDARY_VIA_INIT */ extern cpumask_t cpu_initialized; +static inline int alloc_cpu_id(void) +{ + cpumask_t tmp_map; + int cpu; + cpus_complement(tmp_map, cpu_present_map); + cpu = first_cpu(tmp_map); + if (cpu >= NR_CPUS) + return -ENODEV; + return cpu; +} + +#ifdef CONFIG_HOTPLUG_CPU +static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS]; +static inline struct task_struct * alloc_idle_task(int cpu) +{ + struct task_struct *idle; + + if ((idle = cpu_idle_tasks[cpu]) != NULL) { + /* initialize thread_struct. we really want to avoid destroy + * idle tread + */ + idle->thread.esp = (unsigned long)(((struct pt_regs *) + (THREAD_SIZE + (unsigned long) idle->thread_info)) - 1); + init_idle(idle, cpu); + return idle; + } + idle = fork_idle(cpu); + + if (!IS_ERR(idle)) + cpu_idle_tasks[cpu] = idle; + return idle; +} +#else +#define alloc_idle_task(cpu) fork_idle(cpu) +#endif -static int __init do_boot_cpu(int apicid) +static int __devinit do_boot_cpu(int apicid, int cpu) /* * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad * (ie clustered apic addressing mode), this is a LOGICAL apic ID. @@ -763,16 +868,17 @@ static int __init do_boot_cpu(int apicid) { struct task_struct *idle; unsigned long boot_error; - int timeout, cpu; + int timeout; unsigned long start_eip; unsigned short nmi_high = 0, nmi_low = 0; - cpu = ++cpucount; + ++cpucount; + /* * We can't use kernel_thread since we must avoid to * reschedule the child. */ - idle = fork_idle(cpu); + idle = alloc_idle_task(cpu); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); idle->thread.eip = (unsigned long) start_secondary; @@ -839,13 +945,16 @@ static int __init do_boot_cpu(int apicid) inquire_remote_apic(apicid); } } - x86_cpu_to_apicid[cpu] = apicid; + if (boot_error) { /* Try to put things back the way they were before ... */ unmap_cpu_to_logical_apicid(cpu); cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */ cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */ cpucount--; + } else { + x86_cpu_to_apicid[cpu] = apicid; + cpu_set(cpu, cpu_present_map); } /* mark "stuck" area as not stuck */ @@ -854,6 +963,75 @@ static int __init do_boot_cpu(int apicid) return boot_error; } +#ifdef CONFIG_HOTPLUG_CPU +void cpu_exit_clear(void) +{ + int cpu = raw_smp_processor_id(); + + idle_task_exit(); + + cpucount --; + cpu_uninit(); + irq_ctx_exit(cpu); + + cpu_clear(cpu, cpu_callout_map); + cpu_clear(cpu, cpu_callin_map); + cpu_clear(cpu, cpu_present_map); + + cpu_clear(cpu, smp_commenced_mask); + unmap_cpu_to_logical_apicid(cpu); +} + +struct warm_boot_cpu_info { + struct completion *complete; + int apicid; + int cpu; +}; + +static void __devinit do_warm_boot_cpu(void *p) +{ + struct warm_boot_cpu_info *info = p; + do_boot_cpu(info->apicid, info->cpu); + complete(info->complete); +} + +int __devinit smp_prepare_cpu(int cpu) +{ + DECLARE_COMPLETION(done); + struct warm_boot_cpu_info info; + struct work_struct task; + int apicid, ret; + + lock_cpu_hotplug(); + apicid = x86_cpu_to_apicid[cpu]; + if (apicid == BAD_APICID) { + ret = -ENODEV; + goto exit; + } + + info.complete = &done; + info.apicid = apicid; + info.cpu = cpu; + INIT_WORK(&task, do_warm_boot_cpu, &info); + + tsc_sync_disabled = 1; + + /* init low mem mapping */ + memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS); + flush_tlb_all(); + schedule_work(&task); + wait_for_completion(&done); + + tsc_sync_disabled = 0; + zap_low_mappings(); + ret = 0; +exit: + unlock_cpu_hotplug(); + return ret; +} +#endif + static void smp_tune_scheduling (void) { unsigned long cachesize; /* kB */ @@ -895,13 +1073,6 @@ void *xquad_portio; EXPORT_SYMBOL(xquad_portio); #endif -cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; -#ifdef CONFIG_X86_HT -EXPORT_SYMBOL(cpu_sibling_map); -#endif -cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; -EXPORT_SYMBOL(cpu_core_map); - static void __init smp_boot_cpus(unsigned int max_cpus) { int apicid, cpu, bit, kicked; @@ -1013,7 +1184,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) if (max_cpus <= cpucount+1) continue; - if (do_boot_cpu(apicid)) + if (((cpu = alloc_cpu_id()) <= 0) || do_boot_cpu(apicid, cpu)) printk("CPU #%d not responding - cannot use it.\n", apicid); else @@ -1065,44 +1236,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpus_clear(cpu_core_map[cpu]); } - for (cpu = 0; cpu < NR_CPUS; cpu++) { - struct cpuinfo_x86 *c = cpu_data + cpu; - int siblings = 0; - int i; - if (!cpu_isset(cpu, cpu_callout_map)) - continue; - - if (smp_num_siblings > 1) { - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_isset(i, cpu_callout_map)) - continue; - if (cpu_core_id[cpu] == cpu_core_id[i]) { - siblings++; - cpu_set(i, cpu_sibling_map[cpu]); - } - } - } else { - siblings++; - cpu_set(cpu, cpu_sibling_map[cpu]); - } - - if (siblings != smp_num_siblings) { - printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings); - smp_num_siblings = siblings; - } - - if (c->x86_num_cores > 1) { - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_isset(i, cpu_callout_map)) - continue; - if (phys_proc_id[cpu] == phys_proc_id[i]) { - cpu_set(i, cpu_core_map[cpu]); - } - } - } else { - cpu_core_map[cpu] = cpu_sibling_map[cpu]; - } - } + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); smpboot_setup_io_apic(); @@ -1119,6 +1254,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus) who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ void __init smp_prepare_cpus(unsigned int max_cpus) { + smp_commenced_mask = cpumask_of_cpu(0); + cpu_callin_map = cpumask_of_cpu(0); + mb(); smp_boot_cpus(max_cpus); } @@ -1126,23 +1264,98 @@ void __devinit smp_prepare_boot_cpu(void) { cpu_set(smp_processor_id(), cpu_online_map); cpu_set(smp_processor_id(), cpu_callout_map); + cpu_set(smp_processor_id(), cpu_present_map); + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; } -int __devinit __cpu_up(unsigned int cpu) +#ifdef CONFIG_HOTPLUG_CPU +static void +remove_siblinginfo(int cpu) { - /* This only works at boot for x86. See "rewrite" above. */ - if (cpu_isset(cpu, smp_commenced_mask)) { - local_irq_enable(); - return -ENOSYS; + int sibling; + + for_each_cpu_mask(sibling, cpu_sibling_map[cpu]) + cpu_clear(cpu, cpu_sibling_map[sibling]); + for_each_cpu_mask(sibling, cpu_core_map[cpu]) + cpu_clear(cpu, cpu_core_map[sibling]); + cpus_clear(cpu_sibling_map[cpu]); + cpus_clear(cpu_core_map[cpu]); + phys_proc_id[cpu] = BAD_APICID; + cpu_core_id[cpu] = BAD_APICID; +} + +int __cpu_disable(void) +{ + cpumask_t map = cpu_online_map; + int cpu = smp_processor_id(); + + /* + * Perhaps use cpufreq to drop frequency, but that could go + * into generic code. + * + * We won't take down the boot processor on i386 due to some + * interrupts only being able to be serviced by the BSP. + * Especially so if we're not using an IOAPIC -zwane + */ + if (cpu == 0) + return -EBUSY; + + /* We enable the timer again on the exit path of the death loop */ + disable_APIC_timer(); + /* Allow any queued timer interrupts to get serviced */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); + + remove_siblinginfo(cpu); + + cpu_clear(cpu, map); + fixup_irqs(map); + /* It's now safe to remove this processor from the online map */ + cpu_clear(cpu, cpu_online_map); + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + /* We don't do anything here: idle task is faking death itself. */ + unsigned int i; + + for (i = 0; i < 10; i++) { + /* They ack this in play_dead by setting CPU_DEAD */ + if (per_cpu(cpu_state, cpu) == CPU_DEAD) { + printk ("CPU %d is now offline\n", cpu); + return; + } + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); } + printk(KERN_ERR "CPU %u didn't die...\n", cpu); +} +#else /* ... !CONFIG_HOTPLUG_CPU */ +int __cpu_disable(void) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + /* We said "no" in __cpu_disable */ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ +int __devinit __cpu_up(unsigned int cpu) +{ /* In case one didn't come up */ if (!cpu_isset(cpu, cpu_callin_map)) { + printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); local_irq_enable(); return -EIO; } local_irq_enable(); + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; /* Unleash the CPU! */ cpu_set(cpu, smp_commenced_mask); while (!cpu_isset(cpu, cpu_online_map)) @@ -1156,10 +1369,12 @@ void __init smp_cpus_done(unsigned int max_cpus) setup_ioapic_dest(); #endif zap_low_mappings(); +#ifndef CONFIG_HOTPLUG_CPU /* * Disable executability of the SMP trampoline: */ set_kernel_exec((unsigned long)trampoline_base, trampoline_exec); +#endif } void __init smp_intr_init(void) diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index d408afa..442a6e9 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -283,7 +283,7 @@ ENTRY(sys_call_table) .long sys_mq_timedreceive /* 280 */ .long sys_mq_notify .long sys_mq_getsetattr - .long sys_ni_syscall /* reserved for kexec */ + .long sys_kexec_load .long sys_waitid .long sys_ni_syscall /* 285 */ /* available */ .long sys_add_key diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c index 960d8bd..0bada18 100644 --- a/arch/i386/kernel/sysenter.c +++ b/arch/i386/kernel/sysenter.c @@ -21,11 +21,16 @@ extern asmlinkage void sysenter_entry(void); -void enable_sep_cpu(void *info) +void enable_sep_cpu(void) { int cpu = get_cpu(); struct tss_struct *tss = &per_cpu(init_tss, cpu); + if (!boot_cpu_has(X86_FEATURE_SEP)) { + put_cpu(); + return; + } + tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); @@ -41,7 +46,7 @@ void enable_sep_cpu(void *info) extern const char vsyscall_int80_start, vsyscall_int80_end; extern const char vsyscall_sysenter_start, vsyscall_sysenter_end; -static int __init sysenter_setup(void) +int __init sysenter_setup(void) { void *page = (void *)get_zeroed_page(GFP_ATOMIC); @@ -58,8 +63,5 @@ static int __init sysenter_setup(void) &vsyscall_sysenter_start, &vsyscall_sysenter_end - &vsyscall_sysenter_start); - on_each_cpu(enable_sep_cpu, NULL, 1, 1); return 0; } - -__initcall(sysenter_setup); diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 10a0cbb..658c062 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -50,7 +50,7 @@ static void hpet_writel(unsigned long d, unsigned long a) * comparator value and continue. Next tick can be caught by checking * for a change in the comparator value. Used in apic.c. */ -static void __init wait_hpet_tick(void) +static void __devinit wait_hpet_tick(void) { unsigned int start_cmp_val, end_cmp_val; diff --git a/arch/i386/kernel/timers/common.c b/arch/i386/kernel/timers/common.c index 37353bd..8163fe0 100644 --- a/arch/i386/kernel/timers/common.c +++ b/arch/i386/kernel/timers/common.c @@ -86,7 +86,7 @@ bad_ctc: #define CALIBRATE_CNT_HPET (5 * hpet_tick) #define CALIBRATE_TIME_HPET (5 * KERNEL_TICK_USEC) -unsigned long __init calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr) +unsigned long __devinit calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr) { unsigned long tsc_startlow, tsc_starthigh; unsigned long tsc_endlow, tsc_endhigh; diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index 54c36b1..f46e625 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -33,7 +33,7 @@ static struct timer_opts timer_tsc; static inline void cpufreq_delayed_get(void); -int tsc_disable __initdata = 0; +int tsc_disable __devinitdata = 0; extern spinlock_t i8253_lock; diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index e4d4e21..a61f33d 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -27,6 +27,7 @@ #include <linux/ptrace.h> #include <linux/utsname.h> #include <linux/kprobes.h> +#include <linux/kexec.h> #ifdef CONFIG_EISA #include <linux/ioport.h> @@ -234,22 +235,22 @@ void show_registers(struct pt_regs *regs) * time of the fault.. */ if (in_kernel) { - u8 *eip; + u8 __user *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - eip = (u8 *)regs->eip - 43; + eip = (u8 __user *)regs->eip - 43; for (i = 0; i < 64; i++, eip++) { unsigned char c; - if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) { + if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { printk(" Bad EIP value."); break; } - if (eip == (u8 *)regs->eip) + if (eip == (u8 __user *)regs->eip) printk("<%02x> ", c); else printk("%02x ", c); @@ -273,13 +274,13 @@ static void handle_BUG(struct pt_regs *regs) if (eip < PAGE_OFFSET) goto no_bug; - if (__get_user(ud2, (unsigned short *)eip)) + if (__get_user(ud2, (unsigned short __user *)eip)) goto no_bug; if (ud2 != 0x0b0f) goto no_bug; - if (__get_user(line, (unsigned short *)(eip + 2))) + if (__get_user(line, (unsigned short __user *)(eip + 2))) goto bug; - if (__get_user(file, (char **)(eip + 4)) || + if (__get_user(file, (char * __user *)(eip + 4)) || (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) file = "<bad filename>"; @@ -294,6 +295,9 @@ bug: printk("Kernel BUG\n"); } +/* This is gone through when something in the kernel + * has done something bad and is about to be terminated. +*/ void die(const char * str, struct pt_regs * regs, long err) { static struct { @@ -341,6 +345,10 @@ void die(const char * str, struct pt_regs * regs, long err) bust_spinlocks(0); die.lock_owner = -1; spin_unlock_irq(&die.lock); + + if (kexec_should_crash(current)) + crash_kexec(regs); + if (in_interrupt()) panic("Fatal exception in interrupt"); @@ -361,6 +369,10 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e static void do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { + struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + if (regs->eflags & VM_MASK) { if (vm86) goto vm86_trap; @@ -371,9 +383,6 @@ static void do_trap(int trapnr, int signr, char *str, int vm86, goto kernel_trap; trap_signal: { - struct task_struct *tsk = current; - tsk->thread.error_code = error_code; - tsk->thread.trap_no = trapnr; if (info) force_sig_info(signr, info, tsk); else @@ -486,6 +495,9 @@ fastcall void do_general_protection(struct pt_regs * regs, long error_code) } put_cpu(); + current->thread.error_code = error_code; + current->thread.trap_no = 13; + if (regs->eflags & VM_MASK) goto gp_in_vm86; @@ -570,6 +582,15 @@ void die_nmi (struct pt_regs *regs, const char *msg) console_silent(); spin_unlock(&nmi_print_lock); bust_spinlocks(0); + + /* If we are in kernel we are probably nested up pretty bad + * and might aswell get out now while we still can. + */ + if (!user_mode(regs)) { + current->thread.trap_no = 2; + crash_kexec(regs); + } + do_exit(SIGSEGV); } @@ -625,6 +646,14 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code) nmi_enter(); cpu = smp_processor_id(); + +#ifdef CONFIG_HOTPLUG_CPU + if (!cpu_online(cpu)) { + nmi_exit(); + return; + } +#endif + ++nmi_count(cpu); if (!nmi_callback(regs, cpu)) @@ -872,9 +901,9 @@ fastcall void do_simd_coprocessor_error(struct pt_regs * regs, error_code); return; } - die_if_kernel("cache flush denied", regs, error_code); current->thread.trap_no = 19; current->thread.error_code = error_code; + die_if_kernel("cache flush denied", regs, error_code); force_sig(SIGSEGV, current); } } diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index e0512cc..7e01a52 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -2,20 +2,23 @@ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>; */ +#define LOAD_OFFSET __PAGE_OFFSET + #include <asm-generic/vmlinux.lds.h> #include <asm/thread_info.h> #include <asm/page.h> OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) -ENTRY(startup_32) +ENTRY(phys_startup_32) jiffies = jiffies_64; SECTIONS { - . = __PAGE_OFFSET + 0x100000; + . = __KERNEL_START; + phys_startup_32 = startup_32 - LOAD_OFFSET; /* read-only */ _text = .; /* Text and read-only data */ - .text : { + .text : AT(ADDR(.text) - LOAD_OFFSET) { *(.text) SCHED_TEXT LOCK_TEXT @@ -27,49 +30,55 @@ SECTIONS . = ALIGN(16); /* Exception table */ __start___ex_table = .; - __ex_table : { *(__ex_table) } + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } __stop___ex_table = .; RODATA /* writeable */ - .data : { /* Data */ + .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ *(.data) CONSTRUCTORS } . = ALIGN(4096); __nosave_begin = .; - .data_nosave : { *(.data.nosave) } + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } . = ALIGN(4096); __nosave_end = .; . = ALIGN(4096); - .data.page_aligned : { *(.data.idt) } + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.idt) + } . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + *(.data.cacheline_aligned) + } _edata = .; /* End of data section */ . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : { *(.data.init_task) } + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + } /* will be freed after init */ . = ALIGN(4096); /* Init code and data */ __init_begin = .; - .init.text : { + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; *(.init.text) _einittext = .; } - .init.data : { *(.init.data) } + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } . = ALIGN(16); __setup_start = .; - .init.setup : { *(.init.setup) } + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } __setup_end = .; __initcall_start = .; - .initcall.init : { + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { *(.initcall1.init) *(.initcall2.init) *(.initcall3.init) @@ -80,33 +89,41 @@ SECTIONS } __initcall_end = .; __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + *(.con_initcall.init) + } __con_initcall_end = .; SECURITY_INIT . = ALIGN(4); __alt_instructions = .; - .altinstructions : { *(.altinstructions) } + .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { + *(.altinstructions) + } __alt_instructions_end = .; - .altinstr_replacement : { *(.altinstr_replacement) } + .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { + *(.altinstr_replacement) + } /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ - .exit.text : { *(.exit.text) } - .exit.data : { *(.exit.data) } + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } . = ALIGN(4096); __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } __initramfs_end = .; . = ALIGN(32); __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } + .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } __per_cpu_end = .; . = ALIGN(4096); __init_end = .; /* freed after init ends here */ __bss_start = .; /* BSS */ - .bss : { + .bss.page_aligned : AT(ADDR(.bss.page_aligned) - LOAD_OFFSET) { *(.bss.page_aligned) + } + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { *(.bss) } . = ALIGN(4); diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c index 0aa08ea..e5a1a83 100644 --- a/arch/i386/mach-default/setup.c +++ b/arch/i386/mach-default/setup.c @@ -10,6 +10,14 @@ #include <asm/acpi.h> #include <asm/arch_hooks.h> +#ifdef CONFIG_HOTPLUG_CPU +#define DEFAULT_SEND_IPI (1) +#else +#define DEFAULT_SEND_IPI (0) +#endif + +int no_broadcast=DEFAULT_SEND_IPI; + /** * pre_intr_init_hook - initialisation prior to setting up interrupt vectors * @@ -104,3 +112,22 @@ void __init mca_nmi_hook(void) printk("NMI generated from unknown source!\n"); } #endif + +static __init int no_ipi_broadcast(char *str) +{ + get_option(&str, &no_broadcast); + printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" : + "IPI Broadcast"); + return 1; +} + +__setup("no_ipi_broadcast", no_ipi_broadcast); + +static int __init print_ipi_mode(void) +{ + printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" : + "Shortcut"); + return 0; +} + +late_initcall(print_ipi_mode); diff --git a/arch/i386/mach-default/topology.c b/arch/i386/mach-default/topology.c index 5b3e881..23395ff 100644 --- a/arch/i386/mach-default/topology.c +++ b/arch/i386/mach-default/topology.c @@ -73,12 +73,11 @@ static int __init topology_init(void) { int i; - for (i = 0; i < MAX_NUMNODES; i++) { - if (node_online(i)) - arch_register_node(i); - } - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) arch_register_cpu(i); + for_each_online_node(i) + arch_register_node(i); + + for_each_cpu(i) + arch_register_cpu(i); return 0; } @@ -88,8 +87,8 @@ static int __init topology_init(void) { int i; - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) arch_register_cpu(i); + for_each_cpu(i) + arch_register_cpu(i); return 0; } diff --git a/arch/i386/mach-visws/mpparse.c b/arch/i386/mach-visws/mpparse.c index 5a22082..5f3d7e6 100644 --- a/arch/i386/mach-visws/mpparse.c +++ b/arch/i386/mach-visws/mpparse.c @@ -23,7 +23,6 @@ unsigned long mp_lapic_addr; /* Processor that is doing the boot up */ unsigned int boot_cpu_physical_apicid = -1U; -unsigned int boot_cpu_logical_apicid = -1U; /* Bitmask of physically existing CPUs */ physid_mask_t phys_cpu_present_map; @@ -52,10 +51,8 @@ static void __init MP_processor_info (struct mpc_config_processor *m) (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, m->mpc_apicver); - if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) boot_cpu_physical_apicid = m->mpc_apicid; - boot_cpu_logical_apicid = logical_apicid; - } ver = m->mpc_apicver; if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) { diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c index f429c87..b358f07 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c @@ -30,6 +30,8 @@ #include <linux/initrd.h> #include <linux/nodemask.h> #include <linux/module.h> +#include <linux/kexec.h> + #include <asm/e820.h> #include <asm/setup.h> #include <asm/mmzone.h> diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index a509237..8e90339 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -146,7 +146,7 @@ static int __is_prefetch(struct pt_regs *regs, unsigned long addr) if (instr > limit) break; - if (__get_user(opcode, (unsigned char *) instr)) + if (__get_user(opcode, (unsigned char __user *) instr)) break; instr_hi = opcode & 0xf0; @@ -173,7 +173,7 @@ static int __is_prefetch(struct pt_regs *regs, unsigned long addr) scan_more = 0; if (instr > limit) break; - if (__get_user(opcode, (unsigned char *) instr)) + if (__get_user(opcode, (unsigned char __user *) instr)) break; prefetch = (instr_lo == 0xF) && (opcode == 0x0D || opcode == 0x18); @@ -463,6 +463,9 @@ no_context: printk(KERN_ALERT "*pte = %08lx\n", page); } #endif + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; + tsk->thread.error_code = error_code; die("Oops", regs, error_code); bust_spinlocks(0); do_exit(SIGKILL); diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c index 4b7aaf9..b6eb4dc 100644 --- a/arch/i386/mm/highmem.c +++ b/arch/i386/mm/highmem.c @@ -75,6 +75,24 @@ void kunmap_atomic(void *kvaddr, enum km_type type) preempt_check_resched(); } +/* This is the same as kmap_atomic() but can map memory that doesn't + * have a struct page associated with it. + */ +void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) +{ + enum fixed_addresses idx; + unsigned long vaddr; + + inc_preempt_count(); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot)); + __flush_tlb_one(vaddr); + + return (void*) vaddr; +} + struct page *kmap_atomic_to_page(void *ptr) { unsigned long idx, vaddr = (unsigned long)ptr; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 3672e2e..12216b5 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -352,7 +352,7 @@ static void __init pagetable_init (void) #endif } -#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND) +#ifdef CONFIG_SOFTWARE_SUSPEND /* * Swap suspend & friends need this for resume because things like the intel-agp * driver might have split up a kernel 4MB mapping. diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index d393eef..6b25afc 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -243,7 +243,7 @@ void iounmap(volatile void __iomem *addr) write_lock(&vmlist_lock); p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); if (!p) { - printk("iounmap: bad address %p\n", addr); + printk(KERN_WARNING "iounmap: bad address %p\n", addr); goto out_unlock; } diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index 270c59f..bd2f7af 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c @@ -32,9 +32,9 @@ void show_mem(void) unsigned long i; struct page_state ps; - printk("Mem-info:\n"); + printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pgdat_page_nr(pgdat, i); @@ -49,18 +49,18 @@ void show_mem(void) shared += page_count(page) - 1; } } - printk("%d pages of RAM\n", total); - printk("%d pages of HIGHMEM\n",highmem); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + printk(KERN_INFO "%d pages of RAM\n", total); + printk(KERN_INFO "%d pages of HIGHMEM\n", highmem); + printk(KERN_INFO "%d reserved pages\n", reserved); + printk(KERN_INFO "%d pages shared\n", shared); + printk(KERN_INFO "%d pages swap cached\n", cached); get_page_state(&ps); - printk("%lu pages dirty\n", ps.nr_dirty); - printk("%lu pages writeback\n", ps.nr_writeback); - printk("%lu pages mapped\n", ps.nr_mapped); - printk("%lu pages slab\n", ps.nr_slab); - printk("%lu pages pagetables\n", ps.nr_page_table_pages); + printk(KERN_INFO "%lu pages dirty\n", ps.nr_dirty); + printk(KERN_INFO "%lu pages writeback\n", ps.nr_writeback); + printk(KERN_INFO "%lu pages mapped\n", ps.nr_mapped); + printk(KERN_INFO "%lu pages slab\n", ps.nr_slab); + printk(KERN_INFO "%lu pages pagetables\n", ps.nr_page_table_pages); } /* @@ -113,16 +113,16 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) pmd_t *pmd; if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */ - printk ("set_pmd_pfn: vaddr misaligned\n"); + printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n"); return; /* BUG(); */ } if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */ - printk ("set_pmd_pfn: pfn misaligned\n"); + printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n"); return; /* BUG(); */ } pgd = swapper_pg_dir + pgd_index(vaddr); if (pgd_none(*pgd)) { - printk ("set_pmd_pfn: pgd_none\n"); + printk(KERN_WARNING "set_pmd_pfn: pgd_none\n"); return; /* BUG(); */ } pud = pud_offset(pgd, vaddr); diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index 6f521cf..0e6b45b 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -22,9 +22,11 @@ #include <linux/device.h> #include <linux/suspend.h> #include <linux/acpi.h> + #include <asm/uaccess.h> #include <asm/acpi.h> #include <asm/tlbflush.h> +#include <asm/processor.h> static struct saved_context saved_context; @@ -33,8 +35,6 @@ unsigned long saved_context_esp, saved_context_ebp; unsigned long saved_context_esi, saved_context_edi; unsigned long saved_context_eflags; -extern void enable_sep_cpu(void *); - void __save_processor_state(struct saved_context *ctxt) { kernel_fpu_begin(); @@ -44,7 +44,6 @@ void __save_processor_state(struct saved_context *ctxt) */ asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit)); asm volatile ("sidt %0" : "=m" (ctxt->idt_limit)); - asm volatile ("sldt %0" : "=m" (ctxt->ldt)); asm volatile ("str %0" : "=m" (ctxt->tr)); /* @@ -107,7 +106,6 @@ static void fix_processor_context(void) void __restore_processor_state(struct saved_context *ctxt) { - /* * control registers */ @@ -117,6 +115,13 @@ void __restore_processor_state(struct saved_context *ctxt) asm volatile ("movl %0, %%cr0" :: "r" (ctxt->cr0)); /* + * now restore the descriptor tables to their proper values + * ltr is done i fix_processor_context(). + */ + asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit)); + asm volatile ("lidt %0" :: "m" (ctxt->idt_limit)); + + /* * segment registers */ asm volatile ("movw %0, %%es" :: "r" (ctxt->es)); @@ -125,18 +130,10 @@ void __restore_processor_state(struct saved_context *ctxt) asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss)); /* - * now restore the descriptor tables to their proper values - * ltr is done i fix_processor_context(). - */ - asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit)); - asm volatile ("lidt %0" :: "m" (ctxt->idt_limit)); - asm volatile ("lldt %0" :: "m" (ctxt->ldt)); - - /* * sysenter MSRs */ if (boot_cpu_has(X86_FEATURE_SEP)) - enable_sep_cpu(NULL); + enable_sep_cpu(); fix_processor_context(); do_fpu_end(); diff --git a/arch/ia64/kernel/domain.c b/arch/ia64/kernel/domain.c index fe532c9..d65e87b 100644 --- a/arch/ia64/kernel/domain.c +++ b/arch/ia64/kernel/domain.c @@ -14,7 +14,7 @@ #include <linux/topology.h> #include <linux/nodemask.h> -#define SD_NODES_PER_DOMAIN 6 +#define SD_NODES_PER_DOMAIN 16 #ifdef CONFIG_NUMA /** @@ -27,7 +27,7 @@ * * Should use nodemask_t. */ -static int __devinit find_next_best_node(int node, unsigned long *used_nodes) +static int find_next_best_node(int node, unsigned long *used_nodes) { int i, n, val, min_val, best_node = 0; @@ -66,7 +66,7 @@ static int __devinit find_next_best_node(int node, unsigned long *used_nodes) * should be one that prevents unnecessary balancing, but also spreads tasks * out optimally. */ -static cpumask_t __devinit sched_domain_node_span(int node) +static cpumask_t sched_domain_node_span(int node) { int i; cpumask_t span, nodemask; @@ -96,7 +96,7 @@ static cpumask_t __devinit sched_domain_node_span(int node) #ifdef CONFIG_SCHED_SMT static DEFINE_PER_CPU(struct sched_domain, cpu_domains); static struct sched_group sched_group_cpus[NR_CPUS]; -static int __devinit cpu_to_cpu_group(int cpu) +static int cpu_to_cpu_group(int cpu) { return cpu; } @@ -104,7 +104,7 @@ static int __devinit cpu_to_cpu_group(int cpu) static DEFINE_PER_CPU(struct sched_domain, phys_domains); static struct sched_group sched_group_phys[NR_CPUS]; -static int __devinit cpu_to_phys_group(int cpu) +static int cpu_to_phys_group(int cpu) { #ifdef CONFIG_SCHED_SMT return first_cpu(cpu_sibling_map[cpu]); @@ -125,44 +125,36 @@ static struct sched_group *sched_group_nodes[MAX_NUMNODES]; static DEFINE_PER_CPU(struct sched_domain, allnodes_domains); static struct sched_group sched_group_allnodes[MAX_NUMNODES]; -static int __devinit cpu_to_allnodes_group(int cpu) +static int cpu_to_allnodes_group(int cpu) { return cpu_to_node(cpu); } #endif /* - * Set up scheduler domains and groups. Callers must hold the hotplug lock. + * Build sched domains for a given set of cpus and attach the sched domains + * to the individual cpus */ -void __devinit arch_init_sched_domains(void) +void build_sched_domains(const cpumask_t *cpu_map) { int i; - cpumask_t cpu_default_map; /* - * Setup mask for cpus without special case scheduling requirements. - * For now this just excludes isolated cpus, but could be used to - * exclude other special cases in the future. + * Set up domains for cpus specified by the cpu_map. */ - cpus_complement(cpu_default_map, cpu_isolated_map); - cpus_and(cpu_default_map, cpu_default_map, cpu_online_map); - - /* - * Set up domains. Isolated domains just stay on the dummy domain. - */ - for_each_cpu_mask(i, cpu_default_map) { + for_each_cpu_mask(i, *cpu_map) { int group; struct sched_domain *sd = NULL, *p; cpumask_t nodemask = node_to_cpumask(cpu_to_node(i)); - cpus_and(nodemask, nodemask, cpu_default_map); + cpus_and(nodemask, nodemask, *cpu_map); #ifdef CONFIG_NUMA if (num_online_cpus() > SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) { sd = &per_cpu(allnodes_domains, i); *sd = SD_ALLNODES_INIT; - sd->span = cpu_default_map; + sd->span = *cpu_map; group = cpu_to_allnodes_group(i); sd->groups = &sched_group_allnodes[group]; p = sd; @@ -173,7 +165,7 @@ void __devinit arch_init_sched_domains(void) *sd = SD_NODE_INIT; sd->span = sched_domain_node_span(cpu_to_node(i)); sd->parent = p; - cpus_and(sd->span, sd->span, cpu_default_map); + cpus_and(sd->span, sd->span, *cpu_map); #endif p = sd; @@ -190,7 +182,7 @@ void __devinit arch_init_sched_domains(void) group = cpu_to_cpu_group(i); *sd = SD_SIBLING_INIT; sd->span = cpu_sibling_map[i]; - cpus_and(sd->span, sd->span, cpu_default_map); + cpus_and(sd->span, sd->span, *cpu_map); sd->parent = p; sd->groups = &sched_group_cpus[group]; #endif @@ -198,9 +190,9 @@ void __devinit arch_init_sched_domains(void) #ifdef CONFIG_SCHED_SMT /* Set up CPU (sibling) groups */ - for_each_cpu_mask(i, cpu_default_map) { + for_each_cpu_mask(i, *cpu_map) { cpumask_t this_sibling_map = cpu_sibling_map[i]; - cpus_and(this_sibling_map, this_sibling_map, cpu_default_map); + cpus_and(this_sibling_map, this_sibling_map, *cpu_map); if (i != first_cpu(this_sibling_map)) continue; @@ -213,7 +205,7 @@ void __devinit arch_init_sched_domains(void) for (i = 0; i < MAX_NUMNODES; i++) { cpumask_t nodemask = node_to_cpumask(i); - cpus_and(nodemask, nodemask, cpu_default_map); + cpus_and(nodemask, nodemask, *cpu_map); if (cpus_empty(nodemask)) continue; @@ -222,7 +214,7 @@ void __devinit arch_init_sched_domains(void) } #ifdef CONFIG_NUMA - init_sched_build_groups(sched_group_allnodes, cpu_default_map, + init_sched_build_groups(sched_group_allnodes, *cpu_map, &cpu_to_allnodes_group); for (i = 0; i < MAX_NUMNODES; i++) { @@ -233,12 +225,12 @@ void __devinit arch_init_sched_domains(void) cpumask_t covered = CPU_MASK_NONE; int j; - cpus_and(nodemask, nodemask, cpu_default_map); + cpus_and(nodemask, nodemask, *cpu_map); if (cpus_empty(nodemask)) continue; domainspan = sched_domain_node_span(i); - cpus_and(domainspan, domainspan, cpu_default_map); + cpus_and(domainspan, domainspan, *cpu_map); sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL); sched_group_nodes[i] = sg; @@ -266,7 +258,7 @@ void __devinit arch_init_sched_domains(void) int n = (i + j) % MAX_NUMNODES; cpus_complement(notcovered, covered); - cpus_and(tmp, notcovered, cpu_default_map); + cpus_and(tmp, notcovered, *cpu_map); cpus_and(tmp, tmp, domainspan); if (cpus_empty(tmp)) break; @@ -293,7 +285,7 @@ void __devinit arch_init_sched_domains(void) #endif /* Calculate CPU power for physical packages and nodes */ - for_each_cpu_mask(i, cpu_default_map) { + for_each_cpu_mask(i, *cpu_map) { int power; struct sched_domain *sd; #ifdef CONFIG_SCHED_SMT @@ -359,13 +351,35 @@ next_sg: cpu_attach_domain(sd, i); } } +/* + * Set up scheduler domains and groups. Callers must hold the hotplug lock. + */ +void arch_init_sched_domains(const cpumask_t *cpu_map) +{ + cpumask_t cpu_default_map; + + /* + * Setup mask for cpus without special case scheduling requirements. + * For now this just excludes isolated cpus, but could be used to + * exclude other special cases in the future. + */ + cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map); + + build_sched_domains(&cpu_default_map); +} -void __devinit arch_destroy_sched_domains(void) +void arch_destroy_sched_domains(const cpumask_t *cpu_map) { #ifdef CONFIG_NUMA int i; for (i = 0; i < MAX_NUMNODES; i++) { + cpumask_t nodemask = node_to_cpumask(i); struct sched_group *oldsg, *sg = sched_group_nodes[i]; + + cpus_and(nodemask, nodemask, *cpu_map); + if (cpus_empty(nodemask)) + continue; + if (sg == NULL) continue; sg = sg->next; diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 3865f08..623b0a5 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -346,6 +346,7 @@ smp_callin (void) lock_ipi_calllock(); cpu_set(cpuid, cpu_online_map); unlock_ipi_calllock(); + per_cpu(cpu_state, cpuid) = CPU_ONLINE; smp_setup_percpu_timer(); @@ -611,6 +612,7 @@ void __devinit smp_prepare_boot_cpu(void) { cpu_set(smp_processor_id(), cpu_online_map); cpu_set(smp_processor_id(), cpu_callin_map); + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; } /* @@ -688,6 +690,7 @@ int __cpu_disable(void) return -EBUSY; remove_siblinginfo(cpu); + cpu_clear(cpu, cpu_online_map); fixup_irqs(); local_flush_tlb_all(); cpu_clear(cpu, cpu_callin_map); @@ -774,6 +777,7 @@ __cpu_up (unsigned int cpu) if (cpu_isset(cpu, cpu_callin_map)) return -EINVAL; + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; /* Processor goes to start_secondary(), sets online flag */ ret = do_boot_cpu(sapicid, cpu); if (ret < 0) diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h index 1a0aed8..d0ee635 100644 --- a/arch/ia64/sn/kernel/xpc.h +++ b/arch/ia64/sn/kernel/xpc.h @@ -87,7 +87,7 @@ struct xpc_rsvd_page { u8 partid; /* partition ID from SAL */ u8 version; u8 pad[6]; /* pad to u64 align */ - u64 vars_pa; + volatile u64 vars_pa; u64 part_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned; u64 mach_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned; }; @@ -138,7 +138,7 @@ struct xpc_vars { * occupies half a cacheline. */ struct xpc_vars_part { - u64 magic; + volatile u64 magic; u64 openclose_args_pa; /* physical address of open and close args */ u64 GPs_pa; /* physical address of Get/Put values */ @@ -185,8 +185,8 @@ struct xpc_vars_part { * Define a Get/Put value pair (pointers) used with a message queue. */ struct xpc_gp { - s64 get; /* Get value */ - s64 put; /* Put value */ + volatile s64 get; /* Get value */ + volatile s64 put; /* Put value */ }; #define XPC_GP_SIZE \ @@ -231,7 +231,7 @@ struct xpc_openclose_args { */ struct xpc_notify { struct semaphore sema; /* notify semaphore */ - u8 type; /* type of notification */ + volatile u8 type; /* type of notification */ /* the following two fields are only used if type == XPC_N_CALL */ xpc_notify_func func; /* user's notify function */ @@ -439,7 +439,7 @@ struct xpc_partition { /* XPC infrastructure referencing and teardown control */ - u8 setup_state; /* infrastructure setup state */ + volatile u8 setup_state; /* infrastructure setup state */ wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */ atomic_t references; /* #of references to infrastructure */ diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index 0bf6fbc..6d02dac 100644 --- a/arch/ia64/sn/kernel/xpc_channel.c +++ b/arch/ia64/sn/kernel/xpc_channel.c @@ -209,7 +209,7 @@ xpc_setup_infrastructure(struct xpc_partition *part) * With the setting of the partition setup_state to XPC_P_SETUP, we're * declaring that this partition is ready to go. */ - (volatile u8) part->setup_state = XPC_P_SETUP; + part->setup_state = XPC_P_SETUP; /* @@ -227,7 +227,7 @@ xpc_setup_infrastructure(struct xpc_partition *part) xpc_vars_part[partid].IPI_phys_cpuid = cpu_physical_id(smp_processor_id()); xpc_vars_part[partid].nchannels = part->nchannels; - (volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC1; + xpc_vars_part[partid].magic = XPC_VP_MAGIC1; return xpcSuccess; } @@ -355,7 +355,7 @@ xpc_pull_remote_vars_part(struct xpc_partition *part) /* let the other side know that we've pulled their variables */ - (volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC2; + xpc_vars_part[partid].magic = XPC_VP_MAGIC2; } if (pulled_entry->magic == XPC_VP_MAGIC1) { @@ -1183,7 +1183,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) */ xpc_clear_local_msgqueue_flags(ch); - (volatile s64) ch->w_remote_GP.get = ch->remote_GP.get; + ch->w_remote_GP.get = ch->remote_GP.get; dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, " "channel=%d\n", ch->w_remote_GP.get, ch->partid, @@ -1211,7 +1211,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number) */ xpc_clear_remote_msgqueue_flags(ch); - (volatile s64) ch->w_remote_GP.put = ch->remote_GP.put; + ch->w_remote_GP.put = ch->remote_GP.put; dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " "channel=%d\n", ch->w_remote_GP.put, ch->partid, @@ -1875,7 +1875,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, notify = &ch->notify_queue[msg_number % ch->local_nentries]; notify->func = func; notify->key = key; - (volatile u8) notify->type = notify_type; + notify->type = notify_type; // >>> is a mb() needed here? diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c index cd7ed73..578265e 100644 --- a/arch/ia64/sn/kernel/xpc_partition.c +++ b/arch/ia64/sn/kernel/xpc_partition.c @@ -253,7 +253,7 @@ xpc_rsvd_page_init(void) * This signifies to the remote partition that our reserved * page is initialized. */ - (volatile u64) rp->vars_pa = __pa(xpc_vars); + rp->vars_pa = __pa(xpc_vars); return rp; } diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 50311eb..5aef7e4 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -371,10 +371,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } if (!oldset) oldset = ¤t->blocked; diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 94f5a8e..bd9de7b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1416,6 +1416,12 @@ config HIGHMEM bool "High Memory Support" depends on MIPS32 && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX) +config ARCH_FLATMEM_ENABLE + def_bool y + depends on !NUMA + +source "mm/Kconfig" + config SMP bool "Multi-Processing support" depends on CPU_RM9000 || (SIBYTE_SB1250 && !SIBYTE_STANDALONE) || SGI_IP27 diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 6018ca2..3a240e3 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -33,6 +33,7 @@ #include <linux/root_dev.h> #include <linux/highmem.h> #include <linux/console.h> +#include <linux/mmzone.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> @@ -356,6 +357,8 @@ static inline void bootmem_init(void) } #endif + memory_present(0, first_usable_pfn, max_low_pfn); + /* Initialize the boot-time allocator with low memory only. */ bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn); @@ -557,6 +560,7 @@ void __init setup_arch(char **cmdline_p) parse_cmdline_early(); bootmem_init(); + sparse_init(); paging_init(); resource_init(); } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 73843c5..9c9a271 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -128,7 +128,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end, #endif /* CONFIG_MIPS64 */ #endif /* CONFIG_HIGHMEM */ -#ifndef CONFIG_DISCONTIGMEM +#ifndef CONFIG_NEED_MULTIPLE_NODES extern void pagetable_init(void); void __init paging_init(void) @@ -253,7 +253,7 @@ void __init mem_init(void) initsize >> 10, (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); } -#endif /* !CONFIG_DISCONTIGMEM */ +#endif /* !CONFIG_NEED_MULTIPLE_NODES */ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c index 3b88fde..3fe9420 100644 --- a/arch/mips/mm/pgtable.c +++ b/arch/mips/mm/pgtable.c @@ -5,7 +5,7 @@ void show_mem(void) { -#ifndef CONFIG_DISCONTIGMEM /* XXX(hch): later.. */ +#ifndef CONFIG_NEED_MULTIPLE_NODES /* XXX(hch): later.. */ int pfn, total = 0, reserved = 0; int shared = 0, cached = 0; int highmem = 0; diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 848f439..a7835cd 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -88,6 +88,9 @@ config 8xx depends on BROKEN bool "8xx" +config E200 + bool "e200" + config E500 bool "e500" @@ -98,12 +101,12 @@ config PPC_FPU config BOOKE bool - depends on E500 + depends on E200 || E500 default y config FSL_BOOKE bool - depends on E500 + depends on E200 || E500 default y config PTE_64BIT @@ -141,16 +144,16 @@ config ALTIVEC config SPE bool "SPE Support" - depends on E500 + depends on E200 || E500 ---help--- This option enables kernel support for the Signal Processing Extensions (SPE) to the PowerPC processor. The kernel currently supports saving and restoring SPE registers, and turning on the 'spe enable' bit so user processes can execute SPE instructions. - This option is only usefully if you have a processor that supports + This option is only useful if you have a processor that supports SPE (e500, otherwise known as 85xx series), but does not have any - affect on a non-spe cpu (it does, however add code to the kernel). + effect on a non-spe cpu (it does, however add code to the kernel). If in doubt, say Y here. @@ -200,7 +203,7 @@ config TAU_AVERAGE config MATH_EMULATION bool "Math emulation" - depends on 4xx || 8xx || E500 + depends on 4xx || 8xx || E200 || E500 ---help--- Some PowerPC chips designed for embedded applications do not have a floating-point unit and therefore do not implement the @@ -214,6 +217,26 @@ config MATH_EMULATION here. Saying Y here will not hurt performance (on any machine) but will increase the size of the kernel. +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + + In the GameCube implementation, kexec allows you to load and + run DOL files, including kernel and homebrew DOLs. + source "drivers/cpufreq/Kconfig" config CPU_FREQ_PMAC @@ -254,7 +277,7 @@ config PPC_STD_MMU config NOT_COHERENT_CACHE bool - depends on 4xx || 8xx + depends on 4xx || 8xx || E200 default y endmenu diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug index d2e1eea..e16c771 100644 --- a/arch/ppc/Kconfig.debug +++ b/arch/ppc/Kconfig.debug @@ -66,7 +66,7 @@ config SERIAL_TEXT_DEBUG config PPC_OCP bool - depends on IBM_OCP || FSL_OCP || XILINX_OCP + depends on IBM_OCP || XILINX_OCP default y endmenu diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 0432a25..f9b0d77 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -29,7 +29,7 @@ CPP = $(CC) -E $(CFLAGS) CHECKFLAGS += -D__powerpc__ -ifndef CONFIG_E500 +ifndef CONFIG_FSL_BOOKE CFLAGS += -mstring endif @@ -38,6 +38,7 @@ cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_6xx) += -Wa,-maltivec cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec cpu-as-$(CONFIG_E500) += -Wa,-me500 +cpu-as-$(CONFIG_E200) += -Wa,-me200 AFLAGS += $(cpu-as-y) CFLAGS += $(cpu-as-y) diff --git a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c index 6fb4f73..effe4a0 100644 --- a/arch/ppc/boot/openfirmware/chrpmain.c +++ b/arch/ppc/boot/openfirmware/chrpmain.c @@ -39,7 +39,7 @@ char *avail_high; #define SCRATCH_SIZE (128 << 10) -static char scratch[SCRATCH_SIZE]; /* 1MB of scratch space for gunzip */ +static char scratch[SCRATCH_SIZE]; /* 128k of scratch space for gunzip */ typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int); diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index b284451..b1457a8 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -26,7 +26,10 @@ obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o obj-$(CONFIG_TAU) += temp.o obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o +ifndef CONFIG_E200 obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o +endif +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o ifndef CONFIG_MATH_EMULATION obj-$(CONFIG_8xx) += softemu8xx.o diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index 01c2260..50936cd 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c @@ -903,7 +903,30 @@ struct cpu_spec cpu_specs[] = { .dcache_bsize = 32, }, #endif /* CONFIG_44x */ -#ifdef CONFIG_E500 +#ifdef CONFIG_FSL_BOOKE + { /* e200z5 */ + .pvr_mask = 0xfff00000, + .pvr_value = 0x81000000, + .cpu_name = "e200z5", + /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ + .cpu_features = CPU_FTR_USE_TB, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE | + PPC_FEATURE_UNIFIED_CACHE, + .dcache_bsize = 32, + }, + { /* e200z6 */ + .pvr_mask = 0xfff00000, + .pvr_value = 0x81100000, + .cpu_name = "e200z6", + /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ + .cpu_features = CPU_FTR_USE_TB, + .cpu_user_features = PPC_FEATURE_32 | + PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP | + PPC_FEATURE_HAS_EFP_SINGLE | + PPC_FEATURE_UNIFIED_CACHE, + .dcache_bsize = 32, + }, { /* e500 */ .pvr_mask = 0xffff0000, .pvr_value = 0x80200000, diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 8377b6c..d4df686 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -60,6 +60,11 @@ mcheck_transfer_to_handler: TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK) b transfer_to_handler_full + .globl debug_transfer_to_handler +debug_transfer_to_handler: + TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG) + b transfer_to_handler_full + .globl crit_transfer_to_handler crit_transfer_to_handler: TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT) @@ -835,6 +840,10 @@ ret_from_crit_exc: RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) #ifdef CONFIG_BOOKE + .globl ret_from_debug_exc +ret_from_debug_exc: + RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) + .globl ret_from_mcheck_exc ret_from_mcheck_exc: RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h index 9c50f9d..9342acf 100644 --- a/arch/ppc/kernel/head_booke.h +++ b/arch/ppc/kernel/head_booke.h @@ -49,6 +49,7 @@ * * On 40x critical is the only additional level * On 44x/e500 we have critical and machine check + * On e200 we have critical and debug (machine check occurs via critical) * * Additionally we reserve a SPRG for each priority level so we can free up a * GPR to use as the base for indirect access to the exception stacks. This @@ -60,12 +61,16 @@ /* CRIT_SPRG only used in critical exception handling */ #define CRIT_SPRG SPRN_SPRG2 -/* MCHECK_SPRG only used in critical exception handling */ +/* MCHECK_SPRG only used in machine check exception handling */ #define MCHECK_SPRG SPRN_SPRG6W #define MCHECK_STACK_TOP (exception_stack_top - 4096) #define CRIT_STACK_TOP (exception_stack_top) +/* only on e200 for now */ +#define DEBUG_STACK_TOP (exception_stack_top - 4096) +#define DEBUG_SPRG SPRN_SPRG6W + #ifdef CONFIG_SMP #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ mfspr r8,SPRN_PIR; \ @@ -124,6 +129,8 @@ #define CRITICAL_EXCEPTION_PROLOG \ EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1) +#define DEBUG_EXCEPTION_PROLOG \ + EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1) #define MCHECK_EXCEPTION_PROLOG \ EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1) @@ -205,6 +212,60 @@ label: * save (and later restore) the MSR via SPRN_CSRR1, which will still have * the MSR_DE bit set. */ +#ifdef CONFIG_E200 +#define DEBUG_EXCEPTION \ + START_EXCEPTION(Debug); \ + DEBUG_EXCEPTION_PROLOG; \ + \ + /* \ + * If there is a single step or branch-taken exception in an \ + * exception entry sequence, it was probably meant to apply to \ + * the code where the exception occurred (since exception entry \ + * doesn't turn off DE automatically). We simulate the effect \ + * of turning off DE on entry to an exception handler by turning \ + * off DE in the CSRR1 value and clearing the debug status. \ + */ \ + mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ + andis. r10,r10,DBSR_IC@h; \ + beq+ 2f; \ + \ + lis r10,KERNELBASE@h; /* check if exception in vectors */ \ + ori r10,r10,KERNELBASE@l; \ + cmplw r12,r10; \ + blt+ 2f; /* addr below exception vectors */ \ + \ + lis r10,Debug@h; \ + ori r10,r10,Debug@l; \ + cmplw r12,r10; \ + bgt+ 2f; /* addr above exception vectors */ \ + \ + /* here it looks like we got an inappropriate debug exception. */ \ +1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \ + lis r10,DBSR_IC@h; /* clear the IC event */ \ + mtspr SPRN_DBSR,r10; \ + /* restore state and get out */ \ + lwz r10,_CCR(r11); \ + lwz r0,GPR0(r11); \ + lwz r1,GPR1(r11); \ + mtcrf 0x80,r10; \ + mtspr SPRN_DSRR0,r12; \ + mtspr SPRN_DSRR1,r9; \ + lwz r9,GPR9(r11); \ + lwz r12,GPR12(r11); \ + mtspr DEBUG_SPRG,r8; \ + BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \ + lwz r10,GPR10-INT_FRAME_SIZE(r8); \ + lwz r11,GPR11-INT_FRAME_SIZE(r8); \ + mfspr r8,DEBUG_SPRG; \ + \ + RFDI; \ + b .; \ + \ + /* continue normal handling for a critical exception... */ \ +2: mfspr r4,SPRN_DBSR; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc) +#else #define DEBUG_EXCEPTION \ START_EXCEPTION(Debug); \ CRITICAL_EXCEPTION_PROLOG; \ @@ -257,6 +318,7 @@ label: 2: mfspr r4,SPRN_DBSR; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) +#endif #define INSTRUCTION_STORAGE_EXCEPTION \ START_EXCEPTION(InstructionStorage) \ diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index ce36e88..eb804b7 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -102,6 +102,7 @@ invstr: mflr r6 /* Make it accessible */ or r7,r7,r4 mtspr SPRN_MAS6,r7 tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ +#ifndef CONFIG_E200 mfspr r7,SPRN_MAS1 andis. r7,r7,MAS1_VALID@h bne match_TLB @@ -118,6 +119,7 @@ invstr: mflr r6 /* Make it accessible */ or r7,r7,r4 mtspr SPRN_MAS6,r7 tlbsx 0,r6 /* Fall through, we had to match */ +#endif match_TLB: mfspr r7,SPRN_MAS0 rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */ @@ -196,8 +198,10 @@ skpinv: addi r6,r6,1 /* Increment */ /* 4. Clear out PIDs & Search info */ li r6,0 mtspr SPRN_PID0,r6 +#ifndef CONFIG_E200 mtspr SPRN_PID1,r6 mtspr SPRN_PID2,r6 +#endif mtspr SPRN_MAS6,r6 /* 5. Invalidate mapping we started in */ @@ -277,7 +281,9 @@ skpinv: addi r6,r6,1 /* Increment */ SET_IVOR(32, SPEUnavailable); SET_IVOR(33, SPEFloatingPointData); SET_IVOR(34, SPEFloatingPointRound); +#ifndef CONFIG_E200 SET_IVOR(35, PerformanceMonitor); +#endif /* Establish the interrupt vector base */ lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ @@ -285,6 +291,9 @@ skpinv: addi r6,r6,1 /* Increment */ /* Setup the defaults for TLB entries */ li r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l +#ifdef CONFIG_E200 + oris r2,r2,MAS4_TLBSELD(1)@h +#endif mtspr SPRN_MAS4, r2 #if 0 @@ -293,6 +302,12 @@ skpinv: addi r6,r6,1 /* Increment */ oris r2,r2,HID0_DOZE@h mtspr SPRN_HID0, r2 #endif +#ifdef CONFIG_E200 + /* enable dedicated debug exception handling resources (Debug APU) */ + mfspr r2,SPRN_HID0 + ori r2,r2,HID0_DAPUEN@l + mtspr SPRN_HID0,r2 +#endif #if !defined(CONFIG_BDI_SWITCH) /* @@ -414,7 +429,12 @@ interrupt_base: CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) /* Machine Check Interrupt */ +#ifdef CONFIG_E200 + /* no RFMCI, MCSRRs on E200 */ + CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#else MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#endif /* Data Storage Interrupt */ START_EXCEPTION(DataStorage) @@ -520,8 +540,13 @@ interrupt_base: #ifdef CONFIG_PPC_FPU FP_UNAVAILABLE_EXCEPTION #else +#ifdef CONFIG_E200 + /* E200 treats 'normal' floating point instructions as FP Unavail exception */ + EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE) +#else EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) #endif +#endif /* System Call Interrupt */ START_EXCEPTION(SystemCall) @@ -691,6 +716,7 @@ interrupt_base: /* * Local functions */ + /* * Data TLB exceptions will bail out to this point * if they can't resolve the lightweight TLB fault. @@ -761,6 +787,31 @@ END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS) 2: rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */ mtspr SPRN_MAS3, r11 #endif +#ifdef CONFIG_E200 + /* Round robin TLB1 entries assignment */ + mfspr r12, SPRN_MAS0 + + /* Extract TLB1CFG(NENTRY) */ + mfspr r11, SPRN_TLB1CFG + andi. r11, r11, 0xfff + + /* Extract MAS0(NV) */ + andi. r13, r12, 0xfff + addi r13, r13, 1 + cmpw 0, r13, r11 + addi r12, r12, 1 + + /* check if we need to wrap */ + blt 7f + + /* wrap back to first free tlbcam entry */ + lis r13, tlbcam_index@ha + lwz r13, tlbcam_index@l(r13) + rlwimi r12, r13, 0, 20, 31 +7: + mtspr SPRN_MAS0,r12 +#endif /* CONFIG_E200 */ + tlbwe /* Done...restore registers and get out of here. */ diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c new file mode 100644 index 0000000..84d65a8 --- /dev/null +++ b/arch/ppc/kernel/machine_kexec.c @@ -0,0 +1,118 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> + * + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/mm.h> +#include <linux/kexec.h> +#include <linux/delay.h> +#include <linux/reboot.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/hw_irq.h> +#include <asm/cacheflush.h> +#include <asm/machdep.h> + +typedef NORET_TYPE void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long reboot_code_buffer, + unsigned long start_address) ATTRIB_NORET; + +const extern unsigned char relocate_new_kernel[]; +const extern unsigned int relocate_new_kernel_size; + +void machine_shutdown(void) +{ + if (ppc_md.machine_shutdown) + ppc_md.machine_shutdown(); +} + +void machine_crash_shutdown(struct pt_regs *regs) +{ + if (ppc_md.machine_crash_shutdown) + ppc_md.machine_crash_shutdown(); +} + +/* + * Do what every setup is needed on image and the + * reboot code buffer to allow us to avoid allocations + * later. + */ +int machine_kexec_prepare(struct kimage *image) +{ + if (ppc_md.machine_kexec_prepare) + return ppc_md.machine_kexec_prepare(image); + /* + * Fail if platform doesn't provide its own machine_kexec_prepare + * implementation. + */ + return -ENOSYS; +} + +void machine_kexec_cleanup(struct kimage *image) +{ + if (ppc_md.machine_kexec_cleanup) + ppc_md.machine_kexec_cleanup(image); +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) +{ + if (ppc_md.machine_kexec) + ppc_md.machine_kexec(image); + else { + /* + * Fall back to normal restart if platform doesn't provide + * its own kexec function, and user insist to kexec... + */ + machine_restart(NULL); + } + for(;;); +} + +/* + * This is a generic machine_kexec function suitable at least for + * non-OpenFirmware embedded platforms. + * It merely copies the image relocation code to the control page and + * jumps to it. + * A platform specific function may just call this one. + */ +void machine_kexec_simple(struct kimage *image) +{ + unsigned long page_list; + unsigned long reboot_code_buffer, reboot_code_buffer_phys; + relocate_new_kernel_t rnk; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + page_list = image->head; + + /* we need both effective and real address here */ + reboot_code_buffer = + (unsigned long)page_address(image->control_code_page); + reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); + + /* copy our kernel relocation code to the control code page */ + memcpy((void *)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); + + flush_icache_range(reboot_code_buffer, + reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); + printk(KERN_INFO "Bye!\n"); + + /* now call it */ + rnk = (relocate_new_kernel_t) reboot_code_buffer; + (*rnk)(page_list, reboot_code_buffer_phys, image->start); +} + diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 7329ef1..b6a63a4 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -593,6 +593,14 @@ _GLOBAL(flush_instruction_cache) iccci 0,r3 #endif #elif CONFIG_FSL_BOOKE +BEGIN_FTR_SECTION + mfspr r3,SPRN_L1CSR0 + ori r3,r3,L1CSR0_CFI|L1CSR0_CLFC + /* msync; isync recommended here */ + mtspr SPRN_L1CSR0,r3 + isync + blr +END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE) mfspr r3,SPRN_L1CSR1 ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR mtspr SPRN_L1CSR1,r3 @@ -1436,7 +1444,7 @@ _GLOBAL(sys_call_table) .long sys_mq_timedreceive /* 265 */ .long sys_mq_notify .long sys_mq_getsetattr - .long sys_ni_syscall /* 268 reserved for sys_kexec_load */ + .long sys_kexec_load .long sys_add_key .long sys_request_key /* 270 */ .long sys_keyctl diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c index 918f6b2..fa1dad9 100644 --- a/arch/ppc/kernel/perfmon.c +++ b/arch/ppc/kernel/perfmon.c @@ -36,7 +36,7 @@ /* A lock to regulate grabbing the interrupt */ DEFINE_SPINLOCK(perfmon_lock); -#ifdef CONFIG_FSL_BOOKE +#if defined (CONFIG_FSL_BOOKE) && !defined (CONFIG_E200) static void dummy_perf(struct pt_regs *regs) { unsigned int pmgc0 = mfpmr(PMRN_PMGC0); diff --git a/arch/ppc/kernel/relocate_kernel.S b/arch/ppc/kernel/relocate_kernel.S new file mode 100644 index 0000000..7ff69c4 --- /dev/null +++ b/arch/ppc/kernel/relocate_kernel.S @@ -0,0 +1,123 @@ +/* + * relocate_kernel.S - put the kernel image in place to boot + * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> + * + * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <asm/reg.h> +#include <asm/ppc_asm.h> +#include <asm/processor.h> + +#include <asm/kexec.h> + +#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */ + + /* + * Must be relocatable PIC code callable as a C function. + */ + .globl relocate_new_kernel +relocate_new_kernel: + /* r3 = page_list */ + /* r4 = reboot_code_buffer */ + /* r5 = start_address */ + + li r0, 0 + + /* + * Set Machine Status Register to a known status, + * switch the MMU off and jump to 1: in a single step. + */ + + mr r8, r0 + ori r8, r8, MSR_RI|MSR_ME + mtspr SRR1, r8 + addi r8, r4, 1f - relocate_new_kernel + mtspr SRR0, r8 + sync + rfi + +1: + /* from this point address translation is turned off */ + /* and interrupts are disabled */ + + /* set a new stack at the bottom of our page... */ + /* (not really needed now) */ + addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ + stw r0, 0(r1) + + /* Do the copies */ + li r6, 0 /* checksum */ + mr r0, r3 + b 1f + +0: /* top, read another word for the indirection page */ + lwzu r0, 4(r3) + +1: + /* is it a destination page? (r8) */ + rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ + beq 2f + + rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ + b 0b + +2: /* is it an indirection page? (r3) */ + rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ + beq 2f + + rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ + subi r3, r3, 4 + b 0b + +2: /* are we done? */ + rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ + beq 2f + b 3f + +2: /* is it a source page? (r9) */ + rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ + beq 0b + + rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ + + li r7, PAGE_SIZE / 4 + mtctr r7 + subi r9, r9, 4 + subi r8, r8, 4 +9: + lwzu r0, 4(r9) /* do the copy */ + xor r6, r6, r0 + stwu r0, 4(r8) + dcbst 0, r8 + sync + icbi 0, r8 + bdnz 9b + + addi r9, r9, 4 + addi r8, r8, 4 + b 0b + +3: + + /* To be certain of avoiding problems with self-modifying code + * execute a serializing instruction here. + */ + isync + sync + + /* jump to the entry point, usually the setup routine */ + mtlr r5 + blrl + +1: b 1b + +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long relocate_new_kernel_end - relocate_new_kernel + diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 7c8437da..8aaeb6f 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -705,8 +705,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) unsigned long frame, newsp; int signr, ret; - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); + if (try_to_freeze()) { signr = 0; if (!signal_pending(current)) goto no_signal; diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 2ca8ecf..9e6ae56 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -173,13 +173,13 @@ static inline int check_io_access(struct pt_regs *regs) /* On 4xx, the reason for the machine check or program exception is in the ESR. */ #define get_reason(regs) ((regs)->dsisr) -#ifndef CONFIG_E500 +#ifndef CONFIG_FSL_BOOKE #define get_mc_reason(regs) ((regs)->dsisr) #else #define get_mc_reason(regs) (mfspr(SPRN_MCSR)) #endif #define REASON_FP ESR_FP -#define REASON_ILLEGAL ESR_PIL +#define REASON_ILLEGAL (ESR_PIL | ESR_PUO) #define REASON_PRIVILEGED ESR_PPR #define REASON_TRAP ESR_PTR @@ -302,7 +302,25 @@ void MachineCheckException(struct pt_regs *regs) printk("Bus - Instruction Parity Error\n"); if (reason & MCSR_BUS_RPERR) printk("Bus - Read Parity Error\n"); -#else /* !CONFIG_4xx && !CONFIG_E500 */ +#elif defined (CONFIG_E200) + printk("Machine check in kernel mode.\n"); + printk("Caused by (from MCSR=%lx): ", reason); + + if (reason & MCSR_MCP) + printk("Machine Check Signal\n"); + if (reason & MCSR_CP_PERR) + printk("Cache Push Parity Error\n"); + if (reason & MCSR_CPERR) + printk("Cache Parity Error\n"); + if (reason & MCSR_EXCP_ERR) + printk("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n"); + if (reason & MCSR_BUS_IRERR) + printk("Bus - Read Bus Error on instruction fetch\n"); + if (reason & MCSR_BUS_DRERR) + printk("Bus - Read Bus Error on data load\n"); + if (reason & MCSR_BUS_WRERR) + printk("Bus - Write Bus Error on buffered store or cache line push\n"); +#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */ printk("Machine check in kernel mode.\n"); printk("Caused by (from SRR1=%lx): ", reason); switch (reason & 0x601F0000) { diff --git a/arch/ppc/mm/44x_mmu.c b/arch/ppc/mm/44x_mmu.c index 72f7c0d..3d79ce2 100644 --- a/arch/ppc/mm/44x_mmu.c +++ b/arch/ppc/mm/44x_mmu.c @@ -39,7 +39,6 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/bootmem.h> #include <linux/highmem.h> #include <asm/pgalloc.h> diff --git a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c index a7f6161..b7bcbc2 100644 --- a/arch/ppc/mm/4xx_mmu.c +++ b/arch/ppc/mm/4xx_mmu.c @@ -36,7 +36,6 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/bootmem.h> #include <linux/highmem.h> #include <asm/pgalloc.h> diff --git a/arch/ppc/mm/fsl_booke_mmu.c b/arch/ppc/mm/fsl_booke_mmu.c index e07990e..af9ca0e 100644 --- a/arch/ppc/mm/fsl_booke_mmu.c +++ b/arch/ppc/mm/fsl_booke_mmu.c @@ -41,7 +41,6 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/bootmem.h> #include <linux/highmem.h> #include <asm/pgalloc.h> @@ -126,7 +125,7 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys, flags |= _PAGE_COHERENT; #endif - TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index); + TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index) | MAS0_NV(index+1); TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | MAS1_TID(pid); TLBCAM[index].MAS2 = virt & PAGE_MASK; diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index 37ece15..ddd04d4 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -94,20 +94,24 @@ mpc834x_sys_setup_arch(void) /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC83xx_IRQ_EXT1; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC83xx_IRQ_EXT1; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC83xx_IRQ_EXT2; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC83xx_IRQ_EXT2; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index a2ed611..ddd2e9a 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -92,28 +92,34 @@ mpc8540ads_setup_arch(void) /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); - - pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC); - pdata->board_flags = 0; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 3; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } + + if (pdata) { + pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC); + pdata->board_flags = 0; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 3; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6); + } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c index d87dfd5..e183802 100644 --- a/arch/ppc/platforms/85xx/mpc8560_ads.c +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -90,20 +90,24 @@ mpc8560ads_setup_arch(void) /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 0; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 0; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 1; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 1; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index 3dbdd73..165df94 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -129,20 +129,24 @@ sbc8560_setup_arch(void) /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT6; - pdata->phyid = 25; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT6; + pdata->phyid = 25; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); - pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; - pdata->interruptPHY = MPC85xx_IRQ_EXT7; - pdata->phyid = 26; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + if (pdata) { + pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; + pdata->interruptPHY = MPC85xx_IRQ_EXT7; + pdata->phyid = 26; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 9455bb6..bb41265 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -122,19 +122,23 @@ gp3_setup_arch(void) /* setup the board related information for the enet controllers */ pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); -/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 2; - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + if (pdata) { + /* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 2; + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6); + } pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2); -/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ - pdata->interruptPHY = MPC85xx_IRQ_EXT5; - pdata->phyid = 4; - /* fixup phy address */ - pdata->phy_reg_addr += binfo->bi_immr_base; - memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + if (pdata) { + /* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */ + pdata->interruptPHY = MPC85xx_IRQ_EXT5; + pdata->phyid = 4; + /* fixup phy address */ + pdata->phy_reg_addr += binfo->bi_immr_base; + memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); + } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c index 7d0ee30..7d3fbb5 100644 --- a/arch/ppc/platforms/chrp_pci.c +++ b/arch/ppc/platforms/chrp_pci.c @@ -9,7 +9,6 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/ide.h> -#include <linux/bootmem.h> #include <asm/io.h> #include <asm/pgtable.h> diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index eda922a..169dbf6 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c @@ -27,12 +27,12 @@ #include <linux/root_dev.h> #include <linux/delay.h> #include <linux/seq_file.h> -#include <linux/bootmem.h> #include <linux/mtd/physmap.h> #include <linux/mv643xx.h> #ifdef CONFIG_BOOTIMG #include <linux/bootimg.h> #endif +#include <asm/io.h> #include <asm/page.h> #include <asm/time.h> #include <asm/smp.h> diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c index f6ff519..719fb49 100644 --- a/arch/ppc/platforms/pmac_pci.c +++ b/arch/ppc/platforms/pmac_pci.c @@ -17,7 +17,6 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/init.h> -#include <linux/bootmem.h> #include <asm/sections.h> #include <asm/io.h> diff --git a/arch/ppc/syslib/cpm2_common.c b/arch/ppc/syslib/cpm2_common.c index ea5e770..4c19a4a 100644 --- a/arch/ppc/syslib/cpm2_common.c +++ b/arch/ppc/syslib/cpm2_common.c @@ -21,8 +21,8 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/interrupt.h> -#include <linux/bootmem.h> #include <linux/module.h> +#include <asm/io.h> #include <asm/irq.h> #include <asm/mpc8260.h> #include <asm/page.h> diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c index a5a7526..e7148846 100644 --- a/arch/ppc/syslib/indirect_pci.c +++ b/arch/ppc/syslib/indirect_pci.c @@ -14,7 +14,6 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/init.h> -#include <linux/bootmem.h> #include <asm/io.h> #include <asm/prom.h> diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c index 580ed65..8f01e0f 100644 --- a/arch/ppc/syslib/ipic.c +++ b/arch/ppc/syslib/ipic.c @@ -79,7 +79,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 7, }, [17] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_A, .force = IPIC_SEFCR, @@ -87,7 +87,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 5, }, [18] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_A, .force = IPIC_SEFCR, @@ -95,7 +95,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 6, }, [19] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_A, .force = IPIC_SEFCR, @@ -103,7 +103,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 7, }, [20] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_B, .force = IPIC_SEFCR, @@ -111,7 +111,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 4, }, [21] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_B, .force = IPIC_SEFCR, @@ -119,7 +119,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 5, }, [22] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_B, .force = IPIC_SEFCR, @@ -127,7 +127,7 @@ static struct ipic_info ipic_info[] = { .prio_mask = 6, }, [23] = { - .pend = IPIC_SIPNR_H, + .pend = IPIC_SEPNR, .mask = IPIC_SEMSR, .prio = IPIC_SMPRR_B, .force = IPIC_SEFCR, diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c index 7b241e7..cc77177 100644 --- a/arch/ppc/syslib/mv64x60.c +++ b/arch/ppc/syslib/mv64x60.c @@ -17,7 +17,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/string.h> -#include <linux/bootmem.h> #include <linux/spinlock.h> #include <linux/mv643xx.h> diff --git a/arch/ppc/syslib/mv64x60_win.c b/arch/ppc/syslib/mv64x60_win.c index b6f0f5d..5b827e2 100644 --- a/arch/ppc/syslib/mv64x60_win.c +++ b/arch/ppc/syslib/mv64x60_win.c @@ -17,7 +17,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/string.h> -#include <linux/bootmem.h> #include <linux/mv643xx.h> #include <asm/byteorder.h> diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index cb27068..f804f25 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -142,6 +142,23 @@ config PPC_SPLPAR processors, that is, which share physical processors between two or more partitions. +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on PPC_MULTIPLATFORM && EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + config IBMVIO depends on PPC_PSERIES || PPC_ISERIES bool @@ -270,26 +287,7 @@ config SCHED_SMT when dealing with POWER5 cpus at a cost of slightly increased overhead in some places. If unsure say N here. -config PREEMPT - bool "Preemptible Kernel" - help - This option reduces the latency of the kernel when reacting to - real-time or interactive events by allowing a low priority process to - be preempted even if it is in kernel mode executing a system call. - - Say Y here if you are building a kernel for a desktop, embedded - or real-time system. Say N if you are unsure. - -config PREEMPT_BKL - bool "Preempt The Big Kernel Lock" - depends on PREEMPT - default y - help - This option reduces the latency of the kernel by making the - big kernel lock preemptible. - - Say Y here if you are building a kernel for a desktop system. - Say N if you are unsure. +source "kernel/Kconfig.preempt" config EEH bool "PCI Extended Error Handling (EEH)" if EMBEDDED diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index dffbfb7..d9b2660 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ bpa_iic.o spider-pic.o +obj-$(CONFIG_KEXEC) += machine_kexec.o obj-$(CONFIG_EEH) += eeh.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 02c8f4e..675c270 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1194,7 +1194,7 @@ _GLOBAL(pSeries_secondary_smp_init) bl .__restore_cpu_setup /* Set up a paca value for this processor. Since we have the - * physical cpu id in r3, we need to search the pacas to find + * physical cpu id in r24, we need to search the pacas to find * which logical id maps to our physical one. */ LOADADDR(r13, paca) /* Get base vaddr of paca array */ @@ -1207,8 +1207,8 @@ _GLOBAL(pSeries_secondary_smp_init) cmpwi r5,NR_CPUS blt 1b -99: HMT_LOW /* Couldn't find our CPU id */ - b 99b + mr r3,r24 /* not found, copy phys to r3 */ + b .kexec_wait /* next kernel might do better */ 2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ /* From now on, r24 is expected to be logica cpuid */ diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index 387923f..02e9662 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c @@ -34,6 +34,7 @@ #include <asm/system.h> #include <asm/time.h> #include <asm/iSeries/ItExtVpdPanel.h> +#include <asm/prom.h> #define MODULE_VERS "1.6" #define MODULE_NAME "lparcfg" diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c new file mode 100644 index 0000000..fdb2fc6 --- /dev/null +++ b/arch/ppc64/kernel/machine_kexec.c @@ -0,0 +1,302 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * + * Copyright (C) 2004-2005, IBM Corp. + * + * Created by: Milton D Miller II + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + + +#include <linux/cpumask.h> +#include <linux/kexec.h> +#include <linux/smp.h> +#include <linux/thread_info.h> +#include <linux/errno.h> + +#include <asm/page.h> +#include <asm/current.h> +#include <asm/machdep.h> +#include <asm/cacheflush.h> +#include <asm/paca.h> +#include <asm/mmu.h> +#include <asm/sections.h> /* _end */ +#include <asm/prom.h> + +#define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ + +/* Have this around till we move it into crash specific file */ +note_buf_t crash_notes[NR_CPUS]; + +/* Dummy for now. Not sure if we need to have a crash shutdown in here + * and if what it will achieve. Letting it be now to compile the code + * in generic kexec environment + */ +void machine_crash_shutdown(struct pt_regs *regs) +{ + /* do nothing right now */ + /* smp_relase_cpus() if we want smp on panic kernel */ + /* cpu_irq_down to isolate us until we are ready */ +} + +int machine_kexec_prepare(struct kimage *image) +{ + int i; + unsigned long begin, end; /* limits of segment */ + unsigned long low, high; /* limits of blocked memory range */ + struct device_node *node; + unsigned long *basep; + unsigned int *sizep; + + if (!ppc_md.hpte_clear_all) + return -ENOENT; + + /* + * Since we use the kernel fault handlers and paging code to + * handle the virtual mode, we must make sure no destination + * overlaps kernel static data or bss. + */ + for (i = 0; i < image->nr_segments; i++) + if (image->segment[i].mem < __pa(_end)) + return -ETXTBSY; + + /* + * For non-LPAR, we absolutely can not overwrite the mmu hash + * table, since we are still using the bolted entries in it to + * do the copy. Check that here. + * + * It is safe if the end is below the start of the blocked + * region (end <= low), or if the beginning is after the + * end of the blocked region (begin >= high). Use the + * boolean identity !(a || b) === (!a && !b). + */ + if (htab_address) { + low = __pa(htab_address); + high = low + (htab_hash_mask + 1) * HASH_GROUP_SIZE; + + for (i = 0; i < image->nr_segments; i++) { + begin = image->segment[i].mem; + end = begin + image->segment[i].memsz; + + if ((begin < high) && (end > low)) + return -ETXTBSY; + } + } + + /* We also should not overwrite the tce tables */ + for (node = of_find_node_by_type(NULL, "pci"); node != NULL; + node = of_find_node_by_type(node, "pci")) { + basep = (unsigned long *)get_property(node, "linux,tce-base", + NULL); + sizep = (unsigned int *)get_property(node, "linux,tce-size", + NULL); + if (basep == NULL || sizep == NULL) + continue; + + low = *basep; + high = low + (*sizep); + + for (i = 0; i < image->nr_segments; i++) { + begin = image->segment[i].mem; + end = begin + image->segment[i].memsz; + + if ((begin < high) && (end > low)) + return -ETXTBSY; + } + } + + return 0; +} + +void machine_kexec_cleanup(struct kimage *image) +{ + /* we do nothing in prepare that needs to be undone */ +} + +#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) + +static void copy_segments(unsigned long ind) +{ + unsigned long entry; + unsigned long *ptr; + void *dest; + void *addr; + + /* + * We rely on kexec_load to create a lists that properly + * initializes these pointers before they are used. + * We will still crash if the list is wrong, but at least + * the compiler will be quiet. + */ + ptr = NULL; + dest = NULL; + + for (entry = ind; !(entry & IND_DONE); entry = *ptr++) { + addr = __va(entry & PAGE_MASK); + + switch (entry & IND_FLAGS) { + case IND_DESTINATION: + dest = addr; + break; + case IND_INDIRECTION: + ptr = addr; + break; + case IND_SOURCE: + copy_page(dest, addr); + dest += PAGE_SIZE; + } + } +} + +void kexec_copy_flush(struct kimage *image) +{ + long i, nr_segments = image->nr_segments; + struct kexec_segment ranges[KEXEC_SEGMENT_MAX]; + + /* save the ranges on the stack to efficiently flush the icache */ + memcpy(ranges, image->segment, sizeof(ranges)); + + /* + * After this call we may not use anything allocated in dynamic + * memory, including *image. + * + * Only globals and the stack are allowed. + */ + copy_segments(image->head); + + /* + * we need to clear the icache for all dest pages sometime, + * including ones that were in place on the original copy + */ + for (i = 0; i < nr_segments; i++) + flush_icache_range(ranges[i].mem + KERNELBASE, + ranges[i].mem + KERNELBASE + + ranges[i].memsz); +} + +#ifdef CONFIG_SMP + +/* FIXME: we should schedule this function to be called on all cpus based + * on calling the interrupts, but we would like to call it off irq level + * so that the interrupt controller is clean. + */ +void kexec_smp_down(void *arg) +{ + if (ppc_md.cpu_irq_down) + ppc_md.cpu_irq_down(); + + local_irq_disable(); + kexec_smp_wait(); + /* NOTREACHED */ +} + +static void kexec_prepare_cpus(void) +{ + int my_cpu, i, notified=-1; + + smp_call_function(kexec_smp_down, NULL, 0, /* wait */0); + my_cpu = get_cpu(); + + /* check the others cpus are now down (via paca hw cpu id == -1) */ + for (i=0; i < NR_CPUS; i++) { + if (i == my_cpu) + continue; + + while (paca[i].hw_cpu_id != -1) { + if (!cpu_possible(i)) { + printk("kexec: cpu %d hw_cpu_id %d is not" + " possible, ignoring\n", + i, paca[i].hw_cpu_id); + break; + } + if (!cpu_online(i)) { + /* Fixme: this can be spinning in + * pSeries_secondary_wait with a paca + * waiting for it to go online. + */ + printk("kexec: cpu %d hw_cpu_id %d is not" + " online, ignoring\n", + i, paca[i].hw_cpu_id); + break; + } + if (i != notified) { + printk( "kexec: waiting for cpu %d (physical" + " %d) to go down\n", + i, paca[i].hw_cpu_id); + notified = i; + } + } + } + + /* after we tell the others to go down */ + if (ppc_md.cpu_irq_down) + ppc_md.cpu_irq_down(); + + put_cpu(); + + local_irq_disable(); +} + +#else /* ! SMP */ + +static void kexec_prepare_cpus(void) +{ + /* + * move the secondarys to us so that we can copy + * the new kernel 0-0x100 safely + * + * do this if kexec in setup.c ? + */ + smp_relase_cpus(); + if (ppc_md.cpu_irq_down) + ppc_md.cpu_irq_down(); + local_irq_disable(); +} + +#endif /* SMP */ + +/* + * kexec thread structure and stack. + * + * We need to make sure that this is 16384-byte aligned due to the + * way process stacks are handled. It also must be statically allocated + * or allocated as part of the kimage, because everything else may be + * overwritten when we copy the kexec image. We piggyback on the + * "init_task" linker section here to statically allocate a stack. + * + * We could use a smaller stack if we don't care about anything using + * current, but that audit has not been performed. + */ +union thread_union kexec_stack + __attribute__((__section__(".data.init_task"))) = { }; + +/* Our assembly helper, in kexec_stub.S */ +extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, + void *image, void *control, + void (*clear_all)(void)) ATTRIB_NORET; + +/* too late to fail here */ +void machine_kexec(struct kimage *image) +{ + + /* prepare control code if any */ + + /* shutdown other cpus into our wait loop and quiesce interrupts */ + kexec_prepare_cpus(); + + /* switch to a staticly allocated stack. Based on irq stack code. + * XXX: the task struct will likely be invalid once we do the copy! + */ + kexec_stack.thread_info.task = current_thread_info()->task; + kexec_stack.thread_info.flags = 0; + + /* Some things are best done in assembly. Finding globals with + * a toc is easier in C, so pass in what we can. + */ + kexec_sequence(&kexec_stack, image->start, image, + page_address(image->control_code_page), + ppc_md.hpte_clear_all); + /* NOTREACHED */ +} diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index e3c73b3..f3dea0c 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -680,6 +680,177 @@ _GLOBAL(kernel_thread) ld r30,-16(r1) blr +/* kexec_wait(phys_cpu) + * + * wait for the flag to change, indicating this kernel is going away but + * the slave code for the next one is at addresses 0 to 100. + * + * This is used by all slaves. + * + * Physical (hardware) cpu id should be in r3. + */ +_GLOBAL(kexec_wait) + bl 1f +1: mflr r5 + addi r5,r5,kexec_flag-1b + +99: HMT_LOW +#ifdef CONFIG_KEXEC /* use no memory without kexec */ + lwz r4,0(r5) + cmpwi 0,r4,0 + bnea 0x60 +#endif + b 99b + +/* this can be in text because we won't change it until we are + * running in real anyways + */ +kexec_flag: + .long 0 + + +#ifdef CONFIG_KEXEC + +/* kexec_smp_wait(void) + * + * call with interrupts off + * note: this is a terminal routine, it does not save lr + * + * get phys id from paca + * set paca id to -1 to say we got here + * switch to real mode + * join other cpus in kexec_wait(phys_id) + */ +_GLOBAL(kexec_smp_wait) + lhz r3,PACAHWCPUID(r13) + li r4,-1 + sth r4,PACAHWCPUID(r13) /* let others know we left */ + bl real_mode + b .kexec_wait + +/* + * switch to real mode (turn mmu off) + * we use the early kernel trick that the hardware ignores bits + * 0 and 1 (big endian) of the effective address in real mode + * + * don't overwrite r3 here, it is live for kexec_wait above. + */ +real_mode: /* assume normal blr return */ +1: li r9,MSR_RI + li r10,MSR_DR|MSR_IR + mflr r11 /* return address to SRR0 */ + mfmsr r12 + andc r9,r12,r9 + andc r10,r12,r10 + + mtmsrd r9,1 + mtspr SPRN_SRR1,r10 + mtspr SPRN_SRR0,r11 + rfid + + +/* + * kexec_sequence(newstack, start, image, control, clear_all()) + * + * does the grungy work with stack switching and real mode switches + * also does simple calls to other code + */ + +_GLOBAL(kexec_sequence) + mflr r0 + std r0,16(r1) + + /* switch stacks to newstack -- &kexec_stack.stack */ + stdu r1,THREAD_SIZE-112(r3) + mr r1,r3 + + li r0,0 + std r0,16(r1) + + /* save regs for local vars on new stack. + * yes, we won't go back, but ... + */ + std r31,-8(r1) + std r30,-16(r1) + std r29,-24(r1) + std r28,-32(r1) + std r27,-40(r1) + std r26,-48(r1) + std r25,-56(r1) + + stdu r1,-112-64(r1) + + /* save args into preserved regs */ + mr r31,r3 /* newstack (both) */ + mr r30,r4 /* start (real) */ + mr r29,r5 /* image (virt) */ + mr r28,r6 /* control, unused */ + mr r27,r7 /* clear_all() fn desc */ + mr r26,r8 /* spare */ + lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ + + /* disable interrupts, we are overwriting kernel data next */ + mfmsr r3 + rlwinm r3,r3,0,17,15 + mtmsrd r3,1 + + /* copy dest pages, flush whole dest image */ + mr r3,r29 + bl .kexec_copy_flush /* (image) */ + + /* turn off mmu */ + bl real_mode + + /* clear out hardware hash page table and tlb */ + ld r5,0(r27) /* deref function descriptor */ + mtctr r5 + bctrl /* ppc_md.hash_clear_all(void); */ + +/* + * kexec image calling is: + * the first 0x100 bytes of the entry point are copied to 0 + * + * all slaves branch to slave = 0x60 (absolute) + * slave(phys_cpu_id); + * + * master goes to start = entry point + * start(phys_cpu_id, start, 0); + * + * + * a wrapper is needed to call existing kernels, here is an approximate + * description of one method: + * + * v2: (2.6.10) + * start will be near the boot_block (maybe 0x100 bytes before it?) + * it will have a 0x60, which will b to boot_block, where it will wait + * and 0 will store phys into struct boot-block and load r3 from there, + * copy kernel 0-0x100 and tell slaves to back down to 0x60 again + * + * v1: (2.6.9) + * boot block will have all cpus scanning device tree to see if they + * are the boot cpu ????? + * other device tree differences (prop sizes, va vs pa, etc)... + */ + + /* copy 0x100 bytes starting at start to 0 */ + li r3,0 + mr r4,r30 + li r5,0x100 + li r6,0 + bl .copy_and_flush /* (dest, src, copy limit, start offset) */ +1: /* assume normal blr return */ + + /* release other cpus to the new kernel secondary start at 0x60 */ + mflr r5 + li r6,1 + stw r6,kexec_flag-1b(5) + mr r3,r25 # my phys cpu + mr r4,r30 # start, aka phys mem offset + mtlr 4 + li r5,0 + blr /* image->start(physid, image->start, 0); */ +#endif /* CONFIG_KEXEC */ + /* Why isn't this a) automatic, b) written in 'C'? */ .balign 8 _GLOBAL(sys_call_table32) @@ -951,7 +1122,7 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_mq_timedreceive /* 265 */ .llong .compat_sys_mq_notify .llong .compat_sys_mq_getsetattr - .llong .sys_ni_syscall /* 268 reserved for sys_kexec_load */ + .llong .compat_sys_kexec_load .llong .sys32_add_key .llong .sys32_request_key .llong .compat_sys_keyctl @@ -1227,7 +1398,7 @@ _GLOBAL(sys_call_table) .llong .sys_mq_timedreceive /* 265 */ .llong .sys_mq_notify .llong .sys_mq_getsetattr - .llong .sys_ni_syscall /* 268 reserved for sys_kexec_load */ + .llong .sys_kexec_load .llong .sys_add_key .llong .sys_request_key /* 270 */ .llong .sys_keyctl diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c index 593ea5b..e8fbab1 100644 --- a/arch/ppc64/kernel/mpic.c +++ b/arch/ppc64/kernel/mpic.c @@ -792,6 +792,35 @@ void mpic_setup_this_cpu(void) #endif /* CONFIG_SMP */ } +/* + * XXX: someone who knows mpic should check this. + * do we need to eoi the ipi here (see xics comments)? + * or can we reset the mpic in the new kernel? + */ +void mpic_teardown_this_cpu(void) +{ + struct mpic *mpic = mpic_primary; + unsigned long flags; + u32 msk = 1 << hard_smp_processor_id(); + unsigned int i; + + BUG_ON(mpic == NULL); + + DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); + spin_lock_irqsave(&mpic_lock, flags); + + /* let the mpic know we don't want intrs. */ + for (i = 0; i < mpic->num_sources ; i++) + mpic_irq_write(i, MPIC_IRQ_DESTINATION, + mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk); + + /* Set current processor priority to max */ + mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); + + spin_unlock_irqrestore(&mpic_lock, flags); +} + + void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) { struct mpic *mpic = mpic_primary; diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h index 63e1771..99fbbc9 100644 --- a/arch/ppc64/kernel/mpic.h +++ b/arch/ppc64/kernel/mpic.h @@ -255,6 +255,9 @@ extern unsigned int mpic_irq_get_priority(unsigned int irq); /* Setup a non-boot CPU */ extern void mpic_setup_this_cpu(void); +/* Clean up for kexec (or cpu offline or ...) */ +extern void mpic_teardown_this_cpu(void); + /* Request IPIs on primary mpic */ extern void mpic_request_ipis(void); diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index f2b4124..44d9af7 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -187,14 +187,16 @@ static void __init pSeries_setup_arch(void) { /* Fixup ppc_md depending on the type of interrupt controller */ if (ppc64_interrupt_controller == IC_OPEN_PIC) { - ppc_md.init_IRQ = pSeries_init_mpic; + ppc_md.init_IRQ = pSeries_init_mpic; ppc_md.get_irq = mpic_get_irq; + ppc_md.cpu_irq_down = mpic_teardown_this_cpu; /* Allocate the mpic now, so that find_and_init_phbs() can * fill the ISUs */ pSeries_setup_mpic(); } else { ppc_md.init_IRQ = xics_init_IRQ; ppc_md.get_irq = xics_get_irq; + ppc_md.cpu_irq_down = xics_teardown_cpu; } #ifdef CONFIG_SMP diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 3015414..62c55a1 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -93,10 +93,13 @@ static int query_cpu_stopped(unsigned int pcpu) int pSeries_cpu_disable(void) { + int cpu = smp_processor_id(); + + cpu_clear(cpu, cpu_online_map); systemcfg->processorCount--; /*fix boot_cpuid here*/ - if (smp_processor_id() == boot_cpuid) + if (cpu == boot_cpuid) boot_cpuid = any_online_cpu(cpu_online_map); /* FIXME: abstract this to not be platform specific later on */ diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 0a47a5e..d5e4866 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -677,11 +677,16 @@ void __init setup_system(void) DBG(" <- setup_system()\n"); } - -void machine_restart(char *cmd) +/* also used by kexec */ +void machine_shutdown(void) { if (ppc_md.nvram_sync) ppc_md.nvram_sync(); +} + +void machine_restart(char *cmd) +{ + machine_shutdown(); ppc_md.restart(cmd); #ifdef CONFIG_SMP smp_send_stop(); @@ -690,13 +695,11 @@ void machine_restart(char *cmd) local_irq_disable(); while (1) ; } - EXPORT_SYMBOL(machine_restart); - + void machine_power_off(void) { - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); + machine_shutdown(); ppc_md.power_off(); #ifdef CONFIG_SMP smp_send_stop(); @@ -705,13 +708,11 @@ void machine_power_off(void) local_irq_disable(); while (1) ; } - EXPORT_SYMBOL(machine_power_off); - + void machine_halt(void) { - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); + machine_shutdown(); ppc_md.halt(); #ifdef CONFIG_SMP smp_send_stop(); @@ -720,7 +721,6 @@ void machine_halt(void) local_irq_disable(); while (1) ; } - EXPORT_SYMBOL(machine_halt); static int ppc64_panic_event(struct notifier_block *this, diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index 879f39b..677c445 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -647,6 +647,31 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) } } +void xics_teardown_cpu(void) +{ + int cpu = smp_processor_id(); + int status; + + ops->cppr_info(cpu, 0x00); + iosync(); + + /* + * we need to EOI the IPI if we got here from kexec down IPI + * + * xics doesn't care if we duplicate an EOI as long as we + * don't EOI and raise priority. + * + * probably need to check all the other interrupts too + * should we be flagging idle loop instead? + * or creating some task to be scheduled? + */ + ops->xirr_info_set(cpu, XICS_IPI); + + status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, + (1UL << interrupt_server_size) - 1 - default_distrib_server, 0); + WARN_ON(status != 0); +} + #ifdef CONFIG_HOTPLUG_CPU /* Interrupts are disabled. */ diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c index 52b6b93..4fec058 100644 --- a/arch/ppc64/mm/hash_native.c +++ b/arch/ppc64/mm/hash_native.c @@ -304,6 +304,50 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, local_irq_restore(flags); } +/* + * clear all mappings on kexec. All cpus are in real mode (or they will + * be when they isi), and we are the only one left. We rely on our kernel + * mapping being 0xC0's and the hardware ignoring those two real bits. + * + * TODO: add batching support when enabled. remember, no dynamic memory here, + * athough there is the control page available... + */ +static void native_hpte_clear(void) +{ + unsigned long slot, slots, flags; + HPTE *hptep = htab_address; + Hpte_dword0 dw0; + unsigned long pteg_count; + + pteg_count = htab_hash_mask + 1; + + local_irq_save(flags); + + /* we take the tlbie lock and hold it. Some hardware will + * deadlock if we try to tlbie from two processors at once. + */ + spin_lock(&native_tlbie_lock); + + slots = pteg_count * HPTES_PER_GROUP; + + for (slot = 0; slot < slots; slot++, hptep++) { + /* + * we could lock the pte here, but we are the only cpu + * running, right? and for crash dump, we probably + * don't want to wait for a maybe bad cpu. + */ + dw0 = hptep->dw0.dw0; + + if (dw0.v) { + hptep->dw0.dword0 = 0; + tlbie(slot2va(dw0.avpn, dw0.l, dw0.h, slot), dw0.l); + } + } + + spin_unlock(&native_tlbie_lock); + local_irq_restore(flags); +} + static void native_flush_hash_range(unsigned long context, unsigned long number, int local) { @@ -415,7 +459,8 @@ void hpte_init_native(void) ppc_md.hpte_updatepp = native_hpte_updatepp; ppc_md.hpte_updateboltedpp = native_hpte_updateboltedpp; ppc_md.hpte_insert = native_hpte_insert; - ppc_md.hpte_remove = native_hpte_remove; + ppc_md.hpte_remove = native_hpte_remove; + ppc_md.hpte_clear_all = native_hpte_clear; if (tlb_batching_enabled()) ppc_md.flush_hash_range = native_flush_hash_range; htab_finish_init(); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 32696c1..6600ee8 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -455,6 +455,14 @@ config NO_IDLE_HZ_INIT The HZ timer is switched off in idle by default. That means the HZ timer is already disabled at boot time. +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but is independent of hardware/microcode support. + endmenu config PCMCIA diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 07fd041..89850b2 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -245,6 +245,7 @@ CONFIG_S390_TAPE_BLOCK=y # CONFIG_S390_TAPE_34XX=m # CONFIG_VMLOGRDR is not set +# CONFIG_VMCP is not set # CONFIG_MONREADER is not set # CONFIG_DCSS_SHM is not set diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index b41e0e1..ab1e49d2 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o obj-$(CONFIG_VIRT_TIMER) += vtime.o +# Kexec part +S390_KEXEC_OBJS := machine_kexec.o crash.o +ifeq ($(CONFIG_ARCH_S390X),y) +S390_KEXEC_OBJS += relocate_kernel64.o +else +S390_KEXEC_OBJS += relocate_kernel.o +endif +obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS) + + # # This is just to get the dependencies... # diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 7a607b1..bf52973 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper: lgfr %r5,%r5 # int llgtr %r6,%r6 # struct rusage_emu31 * jg compat_sys_waitid + + .globl compat_sys_kexec_load_wrapper +compat_sys_kexec_load_wrapper: + llgfr %r2,%r2 # unsigned long + llgfr %r3,%r3 # unsigned long + llgtr %r4,%r4 # struct kexec_segment * + llgfr %r5,%r5 # unsigned long + jg compat_sys_kexec_load diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 44df8dc..2006214 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -2,7 +2,7 @@ * arch/s390/kernel/cpcmd.c * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Christian Borntraeger (cborntra@de.ibm.com), */ @@ -18,93 +18,114 @@ #include <asm/system.h> static DEFINE_SPINLOCK(cpcmd_lock); -static char cpcmd_buf[240]; +static char cpcmd_buf[241]; /* * the caller of __cpcmd has to ensure that the response buffer is below 2 GB */ -void __cpcmd(char *cmd, char *response, int rlen) +int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) { const int mask = 0x40000000L; unsigned long flags; + int return_code; + int return_len; int cmdlen; spin_lock_irqsave(&cpcmd_lock, flags); cmdlen = strlen(cmd); BUG_ON(cmdlen > 240); - strcpy(cpcmd_buf, cmd); + memcpy(cpcmd_buf, cmd, cmdlen); ASCEBC(cpcmd_buf, cmdlen); if (response != NULL && rlen > 0) { memset(response, 0, rlen); #ifndef CONFIG_ARCH_S390X - asm volatile ("LRA 2,0(%0)\n\t" - "LR 4,%1\n\t" - "O 4,%4\n\t" - "LRA 3,0(%2)\n\t" - "LR 5,%3\n\t" - ".long 0x83240008 # Diagnose X'08'\n\t" - : /* no output */ - : "a" (cpcmd_buf), "d" (cmdlen), - "a" (response), "d" (rlen), "m" (mask) - : "cc", "2", "3", "4", "5" ); + asm volatile ( "lra 2,0(%2)\n" + "lr 4,%3\n" + "o 4,%6\n" + "lra 3,0(%4)\n" + "lr 5,%5\n" + "diag 2,4,0x8\n" + "brc 8, .Litfits\n" + "ar 5, %5\n" + ".Litfits: \n" + "lr %0,4\n" + "lr %1,5\n" + : "=d" (return_code), "=d" (return_len) + : "a" (cpcmd_buf), "d" (cmdlen), + "a" (response), "d" (rlen), "m" (mask) + : "cc", "2", "3", "4", "5" ); #else /* CONFIG_ARCH_S390X */ - asm volatile (" lrag 2,0(%0)\n" - " lgr 4,%1\n" - " o 4,%4\n" - " lrag 3,0(%2)\n" - " lgr 5,%3\n" - " sam31\n" - " .long 0x83240008 # Diagnose X'08'\n" - " sam64" - : /* no output */ - : "a" (cpcmd_buf), "d" (cmdlen), - "a" (response), "d" (rlen), "m" (mask) - : "cc", "2", "3", "4", "5" ); + asm volatile ( "lrag 2,0(%2)\n" + "lgr 4,%3\n" + "o 4,%6\n" + "lrag 3,0(%4)\n" + "lgr 5,%5\n" + "sam31\n" + "diag 2,4,0x8\n" + "sam64\n" + "brc 8, .Litfits\n" + "agr 5, %5\n" + ".Litfits: \n" + "lgr %0,4\n" + "lgr %1,5\n" + : "=d" (return_code), "=d" (return_len) + : "a" (cpcmd_buf), "d" (cmdlen), + "a" (response), "d" (rlen), "m" (mask) + : "cc", "2", "3", "4", "5" ); #endif /* CONFIG_ARCH_S390X */ EBCASC(response, rlen); } else { + return_len = 0; #ifndef CONFIG_ARCH_S390X - asm volatile ("LRA 2,0(%0)\n\t" - "LR 3,%1\n\t" - ".long 0x83230008 # Diagnose X'08'\n\t" - : /* no output */ - : "a" (cpcmd_buf), "d" (cmdlen) - : "2", "3" ); + asm volatile ( "lra 2,0(%1)\n" + "lr 3,%2\n" + "diag 2,3,0x8\n" + "lr %0,3\n" + : "=d" (return_code) + : "a" (cpcmd_buf), "d" (cmdlen) + : "2", "3" ); #else /* CONFIG_ARCH_S390X */ - asm volatile (" lrag 2,0(%0)\n" - " lgr 3,%1\n" - " sam31\n" - " .long 0x83230008 # Diagnose X'08'\n" - " sam64" - : /* no output */ - : "a" (cpcmd_buf), "d" (cmdlen) - : "2", "3" ); + asm volatile ( "lrag 2,0(%1)\n" + "lgr 3,%2\n" + "sam31\n" + "diag 2,3,0x8\n" + "sam64\n" + "lgr %0,3\n" + : "=d" (return_code) + : "a" (cpcmd_buf), "d" (cmdlen) + : "2", "3" ); #endif /* CONFIG_ARCH_S390X */ } spin_unlock_irqrestore(&cpcmd_lock, flags); + if (response_code != NULL) + *response_code = return_code; + return return_len; } EXPORT_SYMBOL(__cpcmd); #ifdef CONFIG_ARCH_S390X -void cpcmd(char *cmd, char *response, int rlen) +int cpcmd(const char *cmd, char *response, int rlen, int *response_code) { char *lowbuf; + int len; + if ((rlen == 0) || (response == NULL) || !((unsigned long)response >> 31)) - __cpcmd(cmd, response, rlen); + len = __cpcmd(cmd, response, rlen, response_code); else { lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); if (!lowbuf) { printk(KERN_WARNING "cpcmd: could not allocate response buffer\n"); - return; + return -ENOMEM; } - __cpcmd(cmd, lowbuf, rlen); + len = __cpcmd(cmd, lowbuf, rlen, response_code); memcpy(response, lowbuf, rlen); kfree(lowbuf); } + return len; } EXPORT_SYMBOL(cpcmd); diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c new file mode 100644 index 0000000..7bd169c --- /dev/null +++ b/arch/s390/kernel/crash.c @@ -0,0 +1,17 @@ +/* + * arch/s390/kernel/crash.c + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + * + */ + +#include <linux/threads.h> +#include <linux/kexec.h> + +note_buf_t crash_notes[NR_CPUS]; + +void machine_crash_shutdown(struct pt_regs *regs) +{ +} diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 91f8ce5..960ba60 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -19,22 +19,27 @@ #include <linux/sysctl.h> #include <asm/uaccess.h> #include <asm/semaphore.h> - #include <linux/module.h> #include <linux/init.h> +#include <linux/fs.h> +#include <linux/debugfs.h> #include <asm/debug.h> #define DEBUG_PROLOG_ENTRY -1 +#define ALL_AREAS 0 /* copy all debug areas */ +#define NO_AREAS 1 /* copy no debug areas */ + /* typedefs */ typedef struct file_private_info { loff_t offset; /* offset of last read in file */ int act_area; /* number of last formated area */ + int act_page; /* act page in given area */ int act_entry; /* last formated entry (offset */ /* relative to beginning of last */ - /* formated area) */ + /* formated page) */ size_t act_entry_offset; /* up to this offset we copied */ /* in last read the last formated */ /* entry to userland */ @@ -51,8 +56,8 @@ typedef struct * This assumes that all args are converted into longs * on L/390 this is the case for all types of parameter * except of floats, and long long (32 bit) - * - */ + * + */ long args[0]; } debug_sprintf_entry_t; @@ -63,32 +68,38 @@ extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); static int debug_init(void); static ssize_t debug_output(struct file *file, char __user *user_buf, - size_t user_len, loff_t * offset); + size_t user_len, loff_t * offset); static ssize_t debug_input(struct file *file, const char __user *user_buf, - size_t user_len, loff_t * offset); + size_t user_len, loff_t * offset); static int debug_open(struct inode *inode, struct file *file); static int debug_close(struct inode *inode, struct file *file); -static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size); +static debug_info_t* debug_info_create(char *name, int pages_per_area, + int nr_areas, int buf_size); static void debug_info_get(debug_info_t *); static void debug_info_put(debug_info_t *); static int debug_prolog_level_fn(debug_info_t * id, - struct debug_view *view, char *out_buf); + struct debug_view *view, char *out_buf); static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char __user *user_buf, - size_t user_buf_size, loff_t * offset); + struct file *file, const char __user *user_buf, + size_t user_buf_size, loff_t * offset); +static int debug_prolog_pages_fn(debug_info_t * id, + struct debug_view *view, char *out_buf); +static int debug_input_pages_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char __user *user_buf, + size_t user_buf_size, loff_t * offset); static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char __user *user_buf, - size_t user_buf_size, loff_t * offset); + struct file *file, const char __user *user_buf, + size_t user_buf_size, loff_t * offset); static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf); + char *out_buf, const char *in_buf); static int debug_raw_format_fn(debug_info_t * id, - struct debug_view *view, char *out_buf, - const char *in_buf); + struct debug_view *view, char *out_buf, + const char *in_buf); static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, - int area, debug_entry_t * entry, char *out_buf); + int area, debug_entry_t * entry, char *out_buf); static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, debug_sprintf_entry_t *curr_event); + char *out_buf, debug_sprintf_entry_t *curr_event); /* globals */ @@ -119,6 +130,15 @@ struct debug_view debug_level_view = { NULL }; +struct debug_view debug_pages_view = { + "pages", + &debug_prolog_pages_fn, + NULL, + NULL, + &debug_input_pages_fn, + NULL +}; + struct debug_view debug_flush_view = { "flush", NULL, @@ -149,98 +169,161 @@ DECLARE_MUTEX(debug_lock); static int initialized; static struct file_operations debug_file_ops = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .read = debug_output, - .write = debug_input, + .write = debug_input, .open = debug_open, .release = debug_close, }; -static struct proc_dir_entry *debug_proc_root_entry; +static struct dentry *debug_debugfs_root_entry; /* functions */ /* + * debug_areas_alloc + * - Debug areas are implemented as a threedimensonal array: + * areas[areanumber][pagenumber][pageoffset] + */ + +static debug_entry_t*** +debug_areas_alloc(int pages_per_area, int nr_areas) +{ + debug_entry_t*** areas; + int i,j; + + areas = (debug_entry_t ***) kmalloc(nr_areas * + sizeof(debug_entry_t**), + GFP_KERNEL); + if (!areas) + goto fail_malloc_areas; + for (i = 0; i < nr_areas; i++) { + areas[i] = (debug_entry_t**) kmalloc(pages_per_area * + sizeof(debug_entry_t*),GFP_KERNEL); + if (!areas[i]) { + goto fail_malloc_areas2; + } + for(j = 0; j < pages_per_area; j++) { + areas[i][j] = (debug_entry_t*)kmalloc(PAGE_SIZE, + GFP_KERNEL); + if(!areas[i][j]) { + for(j--; j >=0 ; j--) { + kfree(areas[i][j]); + } + kfree(areas[i]); + goto fail_malloc_areas2; + } else { + memset(areas[i][j],0,PAGE_SIZE); + } + } + } + return areas; + +fail_malloc_areas2: + for(i--; i >= 0; i--){ + for(j=0; j < pages_per_area;j++){ + kfree(areas[i][j]); + } + kfree(areas[i]); + } + kfree(areas); +fail_malloc_areas: + return NULL; + +} + + +/* * debug_info_alloc * - alloc new debug-info */ -static debug_info_t* debug_info_alloc(char *name, int page_order, - int nr_areas, int buf_size) +static debug_info_t* +debug_info_alloc(char *name, int pages_per_area, int nr_areas, int buf_size, + int level, int mode) { debug_info_t* rc; - int i; /* alloc everything */ - rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_KERNEL); if(!rc) goto fail_malloc_rc; - rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); - if(!rc->active_entry) - goto fail_malloc_active_entry; - memset(rc->active_entry, 0, nr_areas * sizeof(int)); - rc->areas = (debug_entry_t **) kmalloc(nr_areas * - sizeof(debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) - goto fail_malloc_areas; - for (i = 0; i < nr_areas; i++) { - rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC, - page_order); - if (!rc->areas[i]) { - for (i--; i >= 0; i--) { - free_pages((unsigned long) rc->areas[i], - page_order); - } - goto fail_malloc_areas2; - } else { - memset(rc->areas[i], 0, PAGE_SIZE << page_order); - } + rc->active_entries = (int*)kmalloc(nr_areas * sizeof(int), GFP_KERNEL); + if(!rc->active_entries) + goto fail_malloc_active_entries; + memset(rc->active_entries, 0, nr_areas * sizeof(int)); + rc->active_pages = (int*)kmalloc(nr_areas * sizeof(int), GFP_KERNEL); + if(!rc->active_pages) + goto fail_malloc_active_pages; + memset(rc->active_pages, 0, nr_areas * sizeof(int)); + if((mode == ALL_AREAS) && (pages_per_area != 0)){ + rc->areas = debug_areas_alloc(pages_per_area, nr_areas); + if(!rc->areas) + goto fail_malloc_areas; + } else { + rc->areas = NULL; } /* initialize members */ spin_lock_init(&rc->lock); - rc->page_order = page_order; - rc->nr_areas = nr_areas; - rc->active_area = 0; - rc->level = DEBUG_DEFAULT_LEVEL; - rc->buf_size = buf_size; - rc->entry_size = sizeof(debug_entry_t) + buf_size; - strlcpy(rc->name, name, sizeof(rc->name)); + rc->pages_per_area = pages_per_area; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = level; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + buf_size; + strlcpy(rc->name, name, sizeof(rc->name)-1); memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); -#ifdef CONFIG_PROC_FS - memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * - sizeof(struct proc_dir_entry*)); -#endif /* CONFIG_PROC_FS */ + memset(rc->debugfs_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct dentry*)); atomic_set(&(rc->ref_count), 0); return rc; -fail_malloc_areas2: - kfree(rc->areas); fail_malloc_areas: - kfree(rc->active_entry); -fail_malloc_active_entry: + kfree(rc->active_pages); +fail_malloc_active_pages: + kfree(rc->active_entries); +fail_malloc_active_entries: kfree(rc); fail_malloc_rc: return NULL; } /* - * debug_info_free - * - free memory debug-info + * debug_areas_free + * - free all debug areas */ -static void debug_info_free(debug_info_t* db_info){ - int i; +static void +debug_areas_free(debug_info_t* db_info) +{ + int i,j; + + if(!db_info->areas) + return; for (i = 0; i < db_info->nr_areas; i++) { - free_pages((unsigned long) db_info->areas[i], - db_info->page_order); + for(j = 0; j < db_info->pages_per_area; j++) { + kfree(db_info->areas[i][j]); + } + kfree(db_info->areas[i]); } kfree(db_info->areas); - kfree(db_info->active_entry); + db_info->areas = NULL; +} + +/* + * debug_info_free + * - free memory debug-info + */ + +static void +debug_info_free(debug_info_t* db_info){ + debug_areas_free(db_info); + kfree(db_info->active_entries); + kfree(db_info->active_pages); kfree(db_info); } @@ -249,21 +332,22 @@ static void debug_info_free(debug_info_t* db_info){ * - create new debug-info */ -static debug_info_t* debug_info_create(char *name, int page_order, - int nr_areas, int buf_size) +static debug_info_t* +debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size) { debug_info_t* rc; - rc = debug_info_alloc(name, page_order, nr_areas, buf_size); + rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size, + DEBUG_DEFAULT_LEVEL, ALL_AREAS); if(!rc) goto out; - - /* create proc rood directory */ - rc->proc_root_entry = proc_mkdir(rc->name, debug_proc_root_entry); + /* create root directory */ + rc->debugfs_root_entry = debugfs_create_dir(rc->name, + debug_debugfs_root_entry); /* append new element to linked list */ - if (debug_area_first == NULL) { + if (!debug_area_first) { /* first element in list */ debug_area_first = rc; rc->prev = NULL; @@ -285,17 +369,21 @@ out: * - copy debug-info */ -static debug_info_t* debug_info_copy(debug_info_t* in) +static debug_info_t* +debug_info_copy(debug_info_t* in, int mode) { - int i; + int i,j; debug_info_t* rc; - rc = debug_info_alloc(in->name, in->page_order, - in->nr_areas, in->buf_size); - if(!rc) + + rc = debug_info_alloc(in->name, in->pages_per_area, in->nr_areas, + in->buf_size, in->level, mode); + if(!rc || (mode == NO_AREAS)) goto out; for(i = 0; i < in->nr_areas; i++){ - memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order); + for(j = 0; j < in->pages_per_area; j++) { + memcpy(rc->areas[i][j], in->areas[i][j],PAGE_SIZE); + } } out: return rc; @@ -306,7 +394,8 @@ out: * - increments reference count for debug-info */ -static void debug_info_get(debug_info_t * db_info) +static void +debug_info_get(debug_info_t * db_info) { if (db_info) atomic_inc(&db_info->ref_count); @@ -317,29 +406,20 @@ static void debug_info_get(debug_info_t * db_info) * - decreases reference count for debug-info and frees it if necessary */ -static void debug_info_put(debug_info_t *db_info) +static void +debug_info_put(debug_info_t *db_info) { int i; if (!db_info) return; if (atomic_dec_and_test(&db_info->ref_count)) { -#ifdef DEBUG - printk(KERN_INFO "debug: freeing debug area %p (%s)\n", - db_info, db_info->name); -#endif for (i = 0; i < DEBUG_MAX_VIEWS; i++) { - if (db_info->views[i] == NULL) + if (!db_info->views[i]) continue; -#ifdef CONFIG_PROC_FS - remove_proc_entry(db_info->proc_entries[i]->name, - db_info->proc_root_entry); -#endif + debugfs_remove(db_info->debugfs_entries[i]); } -#ifdef CONFIG_PROC_FS - remove_proc_entry(db_info->proc_root_entry->name, - debug_proc_root_entry); -#endif + debugfs_remove(db_info->debugfs_root_entry); if(db_info == debug_area_first) debug_area_first = db_info->next; if(db_info == debug_area_last) @@ -355,9 +435,9 @@ static void debug_info_put(debug_info_t *db_info) * - format one debug entry and return size of formated data */ -static int debug_format_entry(file_private_info_t *p_info) +static int +debug_format_entry(file_private_info_t *p_info) { - debug_info_t *id_org = p_info->debug_info_org; debug_info_t *id_snap = p_info->debug_info_snap; struct debug_view *view = p_info->view; debug_entry_t *act_entry; @@ -365,22 +445,23 @@ static int debug_format_entry(file_private_info_t *p_info) if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ /* print prolog */ if (view->prolog_proc) - len += view->prolog_proc(id_org, view,p_info->temp_buf); + len += view->prolog_proc(id_snap,view,p_info->temp_buf); goto out; } - - act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + - p_info->act_entry); + if (!id_snap->areas) /* this is true, if we have a prolog only view */ + goto out; /* or if 'pages_per_area' is 0 */ + act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] + [p_info->act_page] + p_info->act_entry); if (act_entry->id.stck == 0LL) goto out; /* empty entry */ if (view->header_proc) - len += view->header_proc(id_org, view, p_info->act_area, + len += view->header_proc(id_snap, view, p_info->act_area, act_entry, p_info->temp_buf + len); if (view->format_proc) - len += view->format_proc(id_org, view, p_info->temp_buf + len, + len += view->format_proc(id_snap, view, p_info->temp_buf + len, DEBUG_DATA(act_entry)); - out: +out: return len; } @@ -389,20 +470,30 @@ static int debug_format_entry(file_private_info_t *p_info) * - goto next entry in p_info */ -extern inline int debug_next_entry(file_private_info_t *p_info) +extern inline int +debug_next_entry(file_private_info_t *p_info) { - debug_info_t *id = p_info->debug_info_snap; + debug_info_t *id; + + id = p_info->debug_info_snap; if(p_info->act_entry == DEBUG_PROLOG_ENTRY){ p_info->act_entry = 0; + p_info->act_page = 0; goto out; } - if ((p_info->act_entry += id->entry_size) - > ((PAGE_SIZE << (id->page_order)) - - id->entry_size)){ - - /* next area */ + if(!id->areas) + return 1; + p_info->act_entry += id->entry_size; + /* switch to next page, if we reached the end of the page */ + if (p_info->act_entry > (PAGE_SIZE - id->entry_size)){ + /* next page */ p_info->act_entry = 0; - p_info->act_area++; + p_info->act_page += 1; + if((p_info->act_page % id->pages_per_area) == 0) { + /* next area */ + p_info->act_area++; + p_info->act_page=0; + } if(p_info->act_area >= id->nr_areas) return 1; } @@ -416,13 +507,14 @@ out: * - copies formated debug entries to the user buffer */ -static ssize_t debug_output(struct file *file, /* file descriptor */ - char __user *user_buf, /* user buffer */ - size_t len, /* length of buffer */ - loff_t *offset) /* offset in the file */ +static ssize_t +debug_output(struct file *file, /* file descriptor */ + char __user *user_buf, /* user buffer */ + size_t len, /* length of buffer */ + loff_t *offset) /* offset in the file */ { size_t count = 0; - size_t entry_offset, size = 0; + size_t entry_offset; file_private_info_t *p_info; p_info = ((file_private_info_t *) file->private_data); @@ -430,27 +522,33 @@ static ssize_t debug_output(struct file *file, /* file descriptor */ return -EPIPE; if(p_info->act_area >= p_info->debug_info_snap->nr_areas) return 0; - entry_offset = p_info->act_entry_offset; - while(count < len){ - size = debug_format_entry(p_info); - size = min((len - count), (size - entry_offset)); - - if(size){ - if (copy_to_user(user_buf + count, - p_info->temp_buf + entry_offset, size)) - return -EFAULT; + int formatted_line_size; + int formatted_line_residue; + int user_buf_residue; + size_t copy_size; + + formatted_line_size = debug_format_entry(p_info); + formatted_line_residue = formatted_line_size - entry_offset; + user_buf_residue = len-count; + copy_size = min(user_buf_residue, formatted_line_residue); + if(copy_size){ + if (copy_to_user(user_buf + count, p_info->temp_buf + + entry_offset, copy_size)) + return -EFAULT; + count += copy_size; + entry_offset += copy_size; } - count += size; - entry_offset = 0; - if(count != len) - if(debug_next_entry(p_info)) + if(copy_size == formatted_line_residue){ + entry_offset = 0; + if(debug_next_entry(p_info)) goto out; + } } out: p_info->offset = *offset + count; - p_info->act_entry_offset = size; + p_info->act_entry_offset = entry_offset; *offset = p_info->offset; return count; } @@ -461,9 +559,9 @@ out: * - calls input function of view */ -static ssize_t debug_input(struct file *file, - const char __user *user_buf, size_t length, - loff_t *offset) +static ssize_t +debug_input(struct file *file, const char __user *user_buf, size_t length, + loff_t *offset) { int rc = 0; file_private_info_t *p_info; @@ -487,26 +585,23 @@ static ssize_t debug_input(struct file *file, * handle */ -static int debug_open(struct inode *inode, struct file *file) +static int +debug_open(struct inode *inode, struct file *file) { int i = 0, rc = 0; file_private_info_t *p_info; debug_info_t *debug_info, *debug_info_snapshot; -#ifdef DEBUG - printk("debug_open\n"); -#endif down(&debug_lock); /* find debug log and view */ - debug_info = debug_area_first; while(debug_info != NULL){ for (i = 0; i < DEBUG_MAX_VIEWS; i++) { - if (debug_info->views[i] == NULL) + if (!debug_info->views[i]) continue; - else if (debug_info->proc_entries[i] == - PDE(file->f_dentry->d_inode)) { + else if (debug_info->debugfs_entries[i] == + file->f_dentry) { goto found; /* found view ! */ } } @@ -516,41 +611,42 @@ static int debug_open(struct inode *inode, struct file *file) rc = -EINVAL; goto out; - found: +found: - /* make snapshot of current debug areas to get it consistent */ + /* Make snapshot of current debug areas to get it consistent. */ + /* To copy all the areas is only needed, if we have a view which */ + /* formats the debug areas. */ - debug_info_snapshot = debug_info_copy(debug_info); + if(!debug_info->views[i]->format_proc && + !debug_info->views[i]->header_proc){ + debug_info_snapshot = debug_info_copy(debug_info, NO_AREAS); + } else { + debug_info_snapshot = debug_info_copy(debug_info, ALL_AREAS); + } if(!debug_info_snapshot){ -#ifdef DEBUG - printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n"); -#endif rc = -ENOMEM; goto out; } - - if ((file->private_data = - kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { -#ifdef DEBUG - printk(KERN_ERR "debug_open: kmalloc failed\n"); -#endif - debug_info_free(debug_info_snapshot); + p_info = (file_private_info_t *) kmalloc(sizeof(file_private_info_t), + GFP_KERNEL); + if(!p_info){ + if(debug_info_snapshot) + debug_info_free(debug_info_snapshot); rc = -ENOMEM; goto out; } - p_info = (file_private_info_t *) file->private_data; p_info->offset = 0; p_info->debug_info_snap = debug_info_snapshot; p_info->debug_info_org = debug_info; p_info->view = debug_info->views[i]; p_info->act_area = 0; + p_info->act_page = 0; p_info->act_entry = DEBUG_PROLOG_ENTRY; p_info->act_entry_offset = 0; - + file->private_data = p_info; debug_info_get(debug_info); - - out: +out: up(&debug_lock); return rc; } @@ -561,14 +657,13 @@ static int debug_open(struct inode *inode, struct file *file) * - deletes private_data area of the file handle */ -static int debug_close(struct inode *inode, struct file *file) +static int +debug_close(struct inode *inode, struct file *file) { file_private_info_t *p_info; -#ifdef DEBUG - printk("debug_close\n"); -#endif p_info = (file_private_info_t *) file->private_data; - debug_info_free(p_info->debug_info_snap); + if(p_info->debug_info_snap) + debug_info_free(p_info->debug_info_snap); debug_info_put(p_info->debug_info_org); kfree(file->private_data); return 0; /* success */ @@ -580,8 +675,8 @@ static int debug_close(struct inode *inode, struct file *file) * - returns handle for debug area */ -debug_info_t *debug_register - (char *name, int page_order, int nr_areas, int buf_size) +debug_info_t* +debug_register (char *name, int pages_per_area, int nr_areas, int buf_size) { debug_info_t *rc = NULL; @@ -591,18 +686,14 @@ debug_info_t *debug_register /* create new debug_info */ - rc = debug_info_create(name, page_order, nr_areas, buf_size); + rc = debug_info_create(name, pages_per_area, nr_areas, buf_size); if(!rc) goto out; debug_register_view(rc, &debug_level_view); debug_register_view(rc, &debug_flush_view); -#ifdef DEBUG - printk(KERN_INFO - "debug: reserved %d areas of %d pages for debugging %s\n", - nr_areas, 1 << page_order, rc->name); -#endif - out: - if (rc == NULL){ + debug_register_view(rc, &debug_pages_view); +out: + if (!rc){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); } up(&debug_lock); @@ -614,27 +705,65 @@ debug_info_t *debug_register * - give back debug area */ -void debug_unregister(debug_info_t * id) +void +debug_unregister(debug_info_t * id) { if (!id) goto out; down(&debug_lock); -#ifdef DEBUG - printk(KERN_INFO "debug: unregistering %s\n", id->name); -#endif debug_info_put(id); up(&debug_lock); - out: +out: return; } /* + * debug_set_size: + * - set area size (number of pages) and number of areas + */ +static int +debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area) +{ + unsigned long flags; + debug_entry_t *** new_areas; + int rc=0; + + if(!id || (nr_areas <= 0) || (pages_per_area < 0)) + return -EINVAL; + if(pages_per_area > 0){ + new_areas = debug_areas_alloc(pages_per_area, nr_areas); + if(!new_areas) { + printk(KERN_WARNING "debug: could not allocate memory "\ + "for pagenumber: %i\n",pages_per_area); + rc = -ENOMEM; + goto out; + } + } else { + new_areas = NULL; + } + spin_lock_irqsave(&id->lock,flags); + debug_areas_free(id); + id->areas = new_areas; + id->nr_areas = nr_areas; + id->pages_per_area = pages_per_area; + id->active_area = 0; + memset(id->active_entries,0,sizeof(int)*id->nr_areas); + memset(id->active_pages, 0, sizeof(int)*id->nr_areas); + spin_unlock_irqrestore(&id->lock,flags); + printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\ + ,id->name, pages_per_area); +out: + return rc; +} + +/* * debug_set_level: * - set actual debug level */ -void debug_set_level(debug_info_t* id, int new_level) +void +debug_set_level(debug_info_t* id, int new_level) { unsigned long flags; if(!id) @@ -649,10 +778,6 @@ void debug_set_level(debug_info_t* id, int new_level) id->name, new_level, 0, DEBUG_MAX_LEVEL); } else { id->level = new_level; -#ifdef DEBUG - printk(KERN_INFO - "debug: %s: new level %i\n",id->name,id->level); -#endif } spin_unlock_irqrestore(&id->lock,flags); } @@ -663,11 +788,16 @@ void debug_set_level(debug_info_t* id, int new_level) * - set active entry to next in the ring buffer */ -extern inline void proceed_active_entry(debug_info_t * id) +extern inline void +proceed_active_entry(debug_info_t * id) { - if ((id->active_entry[id->active_area] += id->entry_size) - > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) - id->active_entry[id->active_area] = 0; + if ((id->active_entries[id->active_area] += id->entry_size) + > (PAGE_SIZE - id->entry_size)){ + id->active_entries[id->active_area] = 0; + id->active_pages[id->active_area] = + (id->active_pages[id->active_area] + 1) % + id->pages_per_area; + } } /* @@ -675,7 +805,8 @@ extern inline void proceed_active_entry(debug_info_t * id) * - set active area to next in the ring buffer */ -extern inline void proceed_active_area(debug_info_t * id) +extern inline void +proceed_active_area(debug_info_t * id) { id->active_area++; id->active_area = id->active_area % id->nr_areas; @@ -685,10 +816,12 @@ extern inline void proceed_active_area(debug_info_t * id) * get_active_entry: */ -extern inline debug_entry_t *get_active_entry(debug_info_t * id) +extern inline debug_entry_t* +get_active_entry(debug_info_t * id) { - return (debug_entry_t *) ((char *) id->areas[id->active_area] + - id->active_entry[id->active_area]); + return (debug_entry_t *) (((char *) id->areas[id->active_area] + [id->active_pages[id->active_area]]) + + id->active_entries[id->active_area]); } /* @@ -696,8 +829,9 @@ extern inline debug_entry_t *get_active_entry(debug_info_t * id) * - set timestamp, caller address, cpu number etc. */ -extern inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active, - int level, int exception) +extern inline void +debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level, + int exception) { STCK(active->id.stck); active->id.fields.cpuid = smp_processor_id(); @@ -721,7 +855,8 @@ static int debug_active=1; * always allow read, allow write only if debug_stoppable is set or * if debug_active is already off */ -static int s390dbf_procactive(ctl_table *table, int write, struct file *filp, +static int +s390dbf_procactive(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { if (!write || debug_stoppable || !debug_active) @@ -766,7 +901,8 @@ static struct ctl_table s390dbf_dir_table[] = { struct ctl_table_header *s390dbf_sysctl_header; -void debug_stop_all(void) +void +debug_stop_all(void) { if (debug_stoppable) debug_active = 0; @@ -778,13 +914,13 @@ void debug_stop_all(void) * - write debug entry with given size */ -debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, - int len) +debug_entry_t* +debug_event_common(debug_info_t * id, int level, const void *buf, int len) { unsigned long flags; debug_entry_t *active; - if (!debug_active) + if (!debug_active || !id->areas) return NULL; spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); @@ -801,13 +937,13 @@ debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf, * - write debug entry with given size and switch to next debug area */ -debug_entry_t *debug_exception_common(debug_info_t * id, int level, - const void *buf, int len) +debug_entry_t +*debug_exception_common(debug_info_t * id, int level, const void *buf, int len) { unsigned long flags; debug_entry_t *active; - if (!debug_active) + if (!debug_active || !id->areas) return NULL; spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); @@ -823,7 +959,8 @@ debug_entry_t *debug_exception_common(debug_info_t * id, int level, * counts arguments in format string for sprintf view */ -extern inline int debug_count_numargs(char *string) +extern inline int +debug_count_numargs(char *string) { int numargs=0; @@ -838,8 +975,8 @@ extern inline int debug_count_numargs(char *string) * debug_sprintf_event: */ -debug_entry_t *debug_sprintf_event(debug_info_t* id, - int level,char *string,...) +debug_entry_t* +debug_sprintf_event(debug_info_t* id, int level,char *string,...) { va_list ap; int numargs,idx; @@ -849,7 +986,7 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id, if((!id) || (level > id->level)) return NULL; - if (!debug_active) + if (!debug_active || !id->areas) return NULL; numargs=debug_count_numargs(string); @@ -871,8 +1008,8 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id, * debug_sprintf_exception: */ -debug_entry_t *debug_sprintf_exception(debug_info_t* id, - int level,char *string,...) +debug_entry_t* +debug_sprintf_exception(debug_info_t* id, int level,char *string,...) { va_list ap; int numargs,idx; @@ -882,7 +1019,7 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id, if((!id) || (level > id->level)) return NULL; - if (!debug_active) + if (!debug_active || !id->areas) return NULL; numargs=debug_count_numargs(string); @@ -906,15 +1043,14 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id, * - is called exactly once to initialize the debug feature */ -static int __init debug_init(void) +static int +__init debug_init(void) { int rc = 0; s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table, 1); down(&debug_lock); -#ifdef CONFIG_PROC_FS - debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL); -#endif /* CONFIG_PROC_FS */ + debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL); printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; up(&debug_lock); @@ -926,13 +1062,14 @@ static int __init debug_init(void) * debug_register_view: */ -int debug_register_view(debug_info_t * id, struct debug_view *view) +int +debug_register_view(debug_info_t * id, struct debug_view *view) { int rc = 0; int i; unsigned long flags; mode_t mode = S_IFREG; - struct proc_dir_entry *pde; + struct dentry *pde; if (!id) goto out; @@ -940,16 +1077,17 @@ int debug_register_view(debug_info_t * id, struct debug_view *view) mode |= S_IRUSR; if (view->input_proc) mode |= S_IWUSR; - pde = create_proc_entry(view->name, mode, id->proc_root_entry); + pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry, + NULL, &debug_file_ops); if (!pde){ - printk(KERN_WARNING "debug: create_proc_entry() failed! Cannot register view %s/%s\n", id->name,view->name); + printk(KERN_WARNING "debug: debugfs_create_file() failed!"\ + " Cannot register view %s/%s\n", id->name,view->name); rc = -1; goto out; } - spin_lock_irqsave(&id->lock, flags); for (i = 0; i < DEBUG_MAX_VIEWS; i++) { - if (id->views[i] == NULL) + if (!id->views[i]) break; } if (i == DEBUG_MAX_VIEWS) { @@ -957,16 +1095,14 @@ int debug_register_view(debug_info_t * id, struct debug_view *view) id->name,view->name); printk(KERN_WARNING "debug: maximum number of views reached (%i)!\n", i); - remove_proc_entry(pde->name, id->proc_root_entry); + debugfs_remove(pde); rc = -1; - } - else { + } else { id->views[i] = view; - pde->proc_fops = &debug_file_ops; - id->proc_entries[i] = pde; + id->debugfs_entries[i] = pde; } spin_unlock_irqrestore(&id->lock, flags); - out: +out: return rc; } @@ -974,7 +1110,8 @@ int debug_register_view(debug_info_t * id, struct debug_view *view) * debug_unregister_view: */ -int debug_unregister_view(debug_info_t * id, struct debug_view *view) +int +debug_unregister_view(debug_info_t * id, struct debug_view *view) { int rc = 0; int i; @@ -990,15 +1127,46 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view) if (i == DEBUG_MAX_VIEWS) rc = -1; else { -#ifdef CONFIG_PROC_FS - remove_proc_entry(id->proc_entries[i]->name, - id->proc_root_entry); -#endif + debugfs_remove(id->debugfs_entries[i]); id->views[i] = NULL; rc = 0; } spin_unlock_irqrestore(&id->lock, flags); - out: +out: + return rc; +} + +static inline char * +debug_get_user_string(const char __user *user_buf, size_t user_len) +{ + char* buffer; + + buffer = kmalloc(user_len + 1, GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + if (copy_from_user(buffer, user_buf, user_len) != 0) { + kfree(buffer); + return ERR_PTR(-EFAULT); + } + /* got the string, now strip linefeed. */ + if (buffer[user_len - 1] == '\n') + buffer[user_len - 1] = 0; + else + buffer[user_len] = 0; + return buffer; +} + +static inline int +debug_get_uint(char *buf) +{ + int rc; + + for(; isspace(*buf); buf++); + rc = simple_strtoul(buf, &buf, 10); + if(*buf){ + printk("debug: no integer specified!\n"); + rc = -EINVAL; + } return rc; } @@ -1011,13 +1179,69 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view) * prints out actual debug level */ -static int debug_prolog_level_fn(debug_info_t * id, +static int +debug_prolog_pages_fn(debug_info_t * id, struct debug_view *view, char *out_buf) { + return sprintf(out_buf, "%i\n", id->pages_per_area); +} + +/* + * reads new size (number of pages per debug area) + */ + +static int +debug_input_pages_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char __user *user_buf, + size_t user_len, loff_t * offset) +{ + char *str; + int rc,new_pages; + + if (user_len > 0x10000) + user_len = 0x10000; + if (*offset != 0){ + rc = -EPIPE; + goto out; + } + str = debug_get_user_string(user_buf,user_len); + if(IS_ERR(str)){ + rc = PTR_ERR(str); + goto out; + } + new_pages = debug_get_uint(str); + if(new_pages < 0){ + rc = -EINVAL; + goto free_str; + } + rc = debug_set_size(id,id->nr_areas, new_pages); + if(rc != 0){ + rc = -EINVAL; + goto free_str; + } + rc = user_len; +free_str: + kfree(str); +out: + *offset += user_len; + return rc; /* number of input characters */ +} + +/* + * prints out actual debug level + */ + +static int +debug_prolog_level_fn(debug_info_t * id, struct debug_view *view, char *out_buf) +{ int rc = 0; - if(id->level == -1) rc = sprintf(out_buf,"-\n"); - else rc = sprintf(out_buf, "%i\n", id->level); + if(id->level == DEBUG_OFF_LEVEL) { + rc = sprintf(out_buf,"-\n"); + } + else { + rc = sprintf(out_buf, "%i\n", id->level); + } return rc; } @@ -1025,30 +1249,43 @@ static int debug_prolog_level_fn(debug_info_t * id, * reads new debug level */ -static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char __user *user_buf, - size_t in_buf_size, loff_t * offset) +static int +debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char __user *user_buf, + size_t user_len, loff_t * offset) { - char input_buf[1]; - int rc = in_buf_size; + char *str; + int rc,new_level; - if (*offset != 0) + if (user_len > 0x10000) + user_len = 0x10000; + if (*offset != 0){ + rc = -EPIPE; goto out; - if (copy_from_user(input_buf, user_buf, 1)){ - rc = -EFAULT; + } + str = debug_get_user_string(user_buf,user_len); + if(IS_ERR(str)){ + rc = PTR_ERR(str); goto out; } - if (isdigit(input_buf[0])) { - int new_level = ((int) input_buf[0] - (int) '0'); - debug_set_level(id, new_level); - } else if(input_buf[0] == '-') { + if(str[0] == '-'){ debug_set_level(id, DEBUG_OFF_LEVEL); + rc = user_len; + goto free_str; } else { - printk(KERN_INFO "debug: level `%c` is not valid\n", - input_buf[0]); + new_level = debug_get_uint(str); } - out: - *offset += in_buf_size; + if(new_level < 0) { + printk(KERN_INFO "debug: level `%s` is not valid\n", str); + rc = -EINVAL; + } else { + debug_set_level(id, new_level); + rc = user_len; + } +free_str: + kfree(str); +out: + *offset += user_len; return rc; /* number of input characters */ } @@ -1057,29 +1294,36 @@ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, * flushes debug areas */ -void debug_flush(debug_info_t* id, int area) +void +debug_flush(debug_info_t* id, int area) { unsigned long flags; - int i; + int i,j; - if(!id) + if(!id || !id->areas) return; spin_lock_irqsave(&id->lock,flags); if(area == DEBUG_FLUSH_ALL){ id->active_area = 0; - memset(id->active_entry, 0, id->nr_areas * sizeof(int)); - for (i = 0; i < id->nr_areas; i++) - memset(id->areas[i], 0, PAGE_SIZE << id->page_order); + memset(id->active_entries, 0, id->nr_areas * sizeof(int)); + for (i = 0; i < id->nr_areas; i++) { + id->active_pages[i] = 0; + for(j = 0; j < id->pages_per_area; j++) { + memset(id->areas[i][j], 0, PAGE_SIZE); + } + } printk(KERN_INFO "debug: %s: all areas flushed\n",id->name); } else if(area >= 0 && area < id->nr_areas) { - id->active_entry[area] = 0; - memset(id->areas[area], 0, PAGE_SIZE << id->page_order); - printk(KERN_INFO - "debug: %s: area %i has been flushed\n", + id->active_entries[area] = 0; + id->active_pages[area] = 0; + for(i = 0; i < id->pages_per_area; i++) { + memset(id->areas[area][i],0,PAGE_SIZE); + } + printk(KERN_INFO "debug: %s: area %i has been flushed\n", id->name, area); } else { printk(KERN_INFO - "debug: %s: area %i cannot be flushed (range: %i - %i)\n", + "debug: %s: area %i cannot be flushed (range: %i - %i)\n", id->name, area, 0, id->nr_areas-1); } spin_unlock_irqrestore(&id->lock,flags); @@ -1089,15 +1333,20 @@ void debug_flush(debug_info_t* id, int area) * view function: flushes debug areas */ -static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view, - struct file *file, const char __user *user_buf, - size_t in_buf_size, loff_t * offset) +static int +debug_input_flush_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char __user *user_buf, + size_t user_len, loff_t * offset) { char input_buf[1]; - int rc = in_buf_size; - - if (*offset != 0) + int rc = user_len; + + if (user_len > 0x10000) + user_len = 0x10000; + if (*offset != 0){ + rc = -EPIPE; goto out; + } if (copy_from_user(input_buf, user_buf, 1)){ rc = -EFAULT; goto out; @@ -1114,8 +1363,8 @@ static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view, printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]); - out: - *offset += in_buf_size; +out: + *offset += user_len; return rc; /* number of input characters */ } @@ -1123,8 +1372,9 @@ static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view, * prints debug header in raw format */ -int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, - int area, debug_entry_t * entry, char *out_buf) +static int +debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) { int rc; @@ -1137,7 +1387,8 @@ int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, * prints debug data in raw format */ -static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, +static int +debug_raw_format_fn(debug_info_t * id, struct debug_view *view, char *out_buf, const char *in_buf) { int rc; @@ -1151,8 +1402,9 @@ static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, * prints debug data in hex/ascii format */ -static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, const char *in_buf) +static int +debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) { int i, rc = 0; @@ -1176,7 +1428,8 @@ static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, * prints header for debug entry */ -int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, +int +debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf) { struct timeval time_val; @@ -1210,8 +1463,9 @@ int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, #define DEBUG_SPRINTF_MAX_ARGS 10 -int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, - char *out_buf, debug_sprintf_entry_t *curr_event) +static int +debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, debug_sprintf_entry_t *curr_event) { int num_longs, num_used_args = 0,i, rc = 0; int index[DEBUG_SPRINTF_MAX_ARGS]; @@ -1251,14 +1505,10 @@ out: /* * clean up module */ -void __exit debug_exit(void) +void +__exit debug_exit(void) { -#ifdef DEBUG - printk("debug_cleanup_module: \n"); -#endif -#ifdef CONFIG_PROC_FS - remove_proc_entry(debug_proc_root_entry->name, NULL); -#endif /* CONFIG_PROC_FS */ + debugfs_remove(debug_debugfs_root_entry); unregister_sysctl_table(s390dbf_sysctl_header); return; } @@ -1266,7 +1516,7 @@ void __exit debug_exit(void) /* * module definitions */ -core_initcall(debug_init); +postcore_initcall(debug_init); module_exit(debug_exit); MODULE_LICENSE("GPL"); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index c0e09b3..5b262b5 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -7,6 +7,7 @@ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Hartmut Penner (hp@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), + * Heiko Carstens <heiko.carstens@de.ibm.com> */ #include <linux/sys.h> @@ -49,9 +50,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) +_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT @@ -121,7 +122,11 @@ STACK_SIZE = 1 << STACK_SHIFT bz BASED(stack_overflow) 3: #endif -2: s %r15,BASED(.Lc_spsize) # make room for registers & psw +2: + .endm + + .macro CREATE_STACK_FRAME psworg,savearea + s %r15,BASED(.Lc_spsize) # make room for registers & psw mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack la %r12,\psworg st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 @@ -161,6 +166,13 @@ __switch_to_base: be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: + l %r4,__THREAD_info(%r2) # get thread_info of prev + tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending? + bz __switch_to_no_mcck-__switch_to_base(%r1) + ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev + l %r4,__THREAD_info(%r3) # get thread_info of next + oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next +__switch_to_no_mcck: stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp @@ -185,6 +197,7 @@ system_call: sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA lh %r7,0x8a # get svc number from lowcore #ifdef CONFIG_VIRT_CPU_ACCOUNTING sysc_vtime: @@ -234,6 +247,8 @@ sysc_work_loop: # One of the work bits is on. Find out which one. # sysc_work: + tm __TI_flags+3(%r9),_TIF_MCCK_PENDING + bo BASED(sysc_mcck_pending) tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bo BASED(sysc_reschedule) tm __TI_flags+3(%r9),_TIF_SIGPENDING @@ -253,6 +268,14 @@ sysc_reschedule: br %r1 # call scheduler # +# _TIF_MCCK_PENDING is set, call handler +# +sysc_mcck_pending: + l %r1,BASED(.Ls390_handle_mcck) + la %r14,BASED(sysc_work_loop) + br %r1 # TIF bit will be cleared by handler + +# # _TIF_SIGPENDING is set, call do_signal # sysc_sigpending: @@ -430,6 +453,7 @@ pgm_check_handler: tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception bnz BASED(pgm_per) # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(pgm_no_vtime) @@ -468,6 +492,7 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(pgm_no_vtime2) @@ -493,6 +518,7 @@ pgm_no_vtime2: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(pgm_no_vtime3) @@ -521,6 +547,7 @@ io_int_handler: stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0 + CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(io_no_vtime) @@ -578,9 +605,11 @@ io_work: lr %r15,%r1 # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED +# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING # io_work_loop: + tm __TI_flags+3(%r9),_TIF_MCCK_PENDING + bo BASED(io_mcck_pending) tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bo BASED(io_reschedule) tm __TI_flags+3(%r9),_TIF_SIGPENDING @@ -588,6 +617,14 @@ io_work_loop: b BASED(io_leave) # +# _TIF_MCCK_PENDING is set, call handler +# +io_mcck_pending: + l %r1,BASED(.Ls390_handle_mcck) + l %r14,BASED(io_work_loop) + br %r1 # TIF bit will be cleared by handler + +# # _TIF_NEED_RESCHED is set, call schedule # io_reschedule: @@ -621,6 +658,7 @@ ext_int_handler: stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+16 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0 + CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(ext_no_vtime) @@ -642,19 +680,62 @@ ext_no_vtime: .globl mcck_int_handler mcck_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer + lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs SAVE_ALL_BASE __LC_SAVE_AREA+32 - SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0 + la %r12,__LC_MCK_OLD_PSW + tm __LC_MCCK_CODE,0x80 # system damage? + bo BASED(mcck_int_main) # yes -> rest of mcck code invalid + tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? + bo BASED(0f) + spt __LC_LAST_UPDATE_TIMER # revalidate cpu timer #ifdef CONFIG_VIRT_CPU_ACCOUNTING - tm SP_PSW+1(%r15),0x01 # interrupting from user ? + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER +0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? + bno BASED(mcck_no_vtime) # no -> skip cleanup critical + tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ? bz BASED(mcck_no_vtime) UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mcck_no_vtime: #endif +0: + tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? + bno BASED(mcck_int_main) # no -> skip cleanup critical + tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit + bnz BASED(mcck_int_main) # from user -> load async stack + clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end) + bhe BASED(mcck_int_main) + clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start) + bl BASED(mcck_int_main) + l %r14,BASED(.Lcleanup_critical) + basr %r14,%r14 +mcck_int_main: + l %r14,__LC_PANIC_STACK # are we already on the panic stack? + slr %r14,%r15 + sra %r14,PAGE_SHIFT + be BASED(0f) + l %r15,__LC_PANIC_STACK # load panic stack +0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32 + l %r9,__LC_THREAD_INFO # load pointer to thread_info struct + la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Ls390_mcck) - basr %r14,%r1 # call machine check handler + basr %r14,%r1 # call machine check handler + tm SP_PSW+1(%r15),0x01 # returning to user ? + bno BASED(mcck_return) + l %r1,__LC_KERNEL_STACK # switch to kernel stack + s %r1,BASED(.Lc_spsize) + mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain + lr %r15,%r1 + stosm __SF_EMPTY(%r15),0x04 # turn dat on + tm __TI_flags+3(%r9),_TIF_MCCK_PENDING + bno BASED(mcck_return) + l %r1,BASED(.Ls390_handle_mcck) + basr %r14,%r1 # call machine check handler mcck_return: RESTORE_ALL 0 @@ -742,7 +823,7 @@ cleanup_critical: clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop) bl BASED(0f) clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4) - bl BASED(cleanup_sysc_leave) + bl BASED(cleanup_sysc_return) 0: br %r14 @@ -760,6 +841,7 @@ cleanup_system_call: mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16 0: st %r13,__LC_SAVE_AREA+20 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA st %r15,__LC_SAVE_AREA+28 lh %r7,0x8a #ifdef CONFIG_VIRT_CPU_ACCOUNTING @@ -834,6 +916,8 @@ cleanup_sysc_leave_insn: * Symbol constants */ .Ls390_mcck: .long s390_do_machine_check +.Ls390_handle_mcck: + .long s390_handle_mcck .Ldo_IRQ: .long do_IRQ .Ldo_extint: .long do_extint .Ldo_signal: .long do_signal diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 51527ab..57ca75d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -7,6 +7,7 @@ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Hartmut Penner (hp@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), + * Heiko Carstens <heiko.carstens@de.ibm.com> */ #include <linux/sys.h> @@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT -_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ +_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \ _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) -_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) +_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) #define BASED(name) name-system_call(%r13) @@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED) jz stack_overflow 3: #endif -2: aghi %r15,-SP_SIZE # make room for registers & psw +2: + .endm + + .macro CREATE_STACK_FRAME psworg,savearea + aghi %r15,-SP_SIZE # make room for registers & psw mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack la %r12,\psworg stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 @@ -152,6 +157,13 @@ __switch_to: je __switch_to_noper # we got away without bashing TLB's lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: + lg %r4,__THREAD_info(%r2) # get thread_info of prev + tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? + jz __switch_to_no_mcck + ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev + lg %r4,__THREAD_info(%r3) # get thread_info of next + oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next +__switch_to_no_mcck: stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp @@ -176,6 +188,7 @@ system_call: sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore #ifdef CONFIG_VIRT_CPU_ACCOUNTING sysc_vtime: @@ -232,6 +245,8 @@ sysc_work_loop: # One of the work bits is on. Find out which one. # sysc_work: + tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + jo sysc_mcck_pending tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jo sysc_reschedule tm __TI_flags+7(%r9),_TIF_SIGPENDING @@ -250,6 +265,13 @@ sysc_reschedule: jg schedule # return point is sysc_return # +# _TIF_MCCK_PENDING is set, call handler +# +sysc_mcck_pending: + larl %r14,sysc_work_loop + jg s390_handle_mcck # TIF bit will be cleared by handler + +# # _TIF_SIGPENDING is set, call do_signal # sysc_sigpending: @@ -474,6 +496,7 @@ pgm_check_handler: tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jnz pgm_per # got per exception -> special case SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime @@ -512,6 +535,7 @@ pgm_per: # pgm_per_std: SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime2 @@ -537,6 +561,7 @@ pgm_no_vtime2: # pgm_svcper: SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime3 @@ -564,6 +589,7 @@ io_int_handler: stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0 + CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz io_no_vtime @@ -621,9 +647,11 @@ io_work: lgr %r15,%r1 # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED +# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING # io_work_loop: + tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + jo io_mcck_pending tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jo io_reschedule tm __TI_flags+7(%r9),_TIF_SIGPENDING @@ -631,6 +659,13 @@ io_work_loop: j io_leave # +# _TIF_MCCK_PENDING is set, call handler +# +io_mcck_pending: + larl %r14,io_work_loop + jg s390_handle_mcck # TIF bit will be cleared by handler + +# # _TIF_NEED_RESCHED is set, call schedule # io_reschedule: @@ -661,6 +696,7 @@ ext_int_handler: stck __LC_INT_CLOCK SAVE_ALL_BASE __LC_SAVE_AREA+32 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0 + CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz ext_no_vtime @@ -680,18 +716,60 @@ ext_no_vtime: */ .globl mcck_int_handler mcck_int_handler: - STORE_TIMER __LC_ASYNC_ENTER_TIMER + la %r1,4095 # revalidate r1 + spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs SAVE_ALL_BASE __LC_SAVE_AREA+64 - SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0 + la %r12,__LC_MCK_OLD_PSW + tm __LC_MCCK_CODE,0x80 # system damage? + jo mcck_int_main # yes -> rest of mcck code invalid + tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? + jo 0f + spt __LC_LAST_UPDATE_TIMER #ifdef CONFIG_VIRT_CPU_ACCOUNTING - tm SP_PSW+1(%r15),0x01 # interrupting from user ? + mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER +0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? + jno mcck_no_vtime # no -> no timer update + tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ? jz mcck_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER mcck_no_vtime: #endif - brasl %r14,s390_do_machine_check +0: + tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? + jno mcck_int_main # no -> skip cleanup critical + tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit + jnz mcck_int_main # from user -> load kernel stack + clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end) + jhe mcck_int_main + clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start) + jl mcck_int_main + brasl %r14,cleanup_critical +mcck_int_main: + lg %r14,__LC_PANIC_STACK # are we already on the panic stack? + slgr %r14,%r15 + srag %r14,%r14,PAGE_SHIFT + jz 0f + lg %r15,__LC_PANIC_STACK # load panic stack +0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 + lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct + la %r2,SP_PTREGS(%r15) # load pt_regs + brasl %r14,s390_do_machine_check + tm SP_PSW+1(%r15),0x01 # returning to user ? + jno mcck_return + lg %r1,__LC_KERNEL_STACK # switch to kernel stack + aghi %r1,-SP_SIZE + mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain + lgr %r15,%r1 + stosm __SF_EMPTY(%r15),0x04 # turn dat on + tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + jno mcck_return + brasl %r14,s390_handle_mcck mcck_return: RESTORE_ALL 0 @@ -775,7 +853,7 @@ cleanup_critical: clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop) jl 0f clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8) - jl cleanup_sysc_leave + jl cleanup_sysc_return 0: br %r14 @@ -793,6 +871,7 @@ cleanup_system_call: mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32 0: stg %r13,__LC_SAVE_AREA+40 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1 + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA stg %r15,__LC_SAVE_AREA+56 llgh %r7,__LC_SVC_INT_CODE #ifdef CONFIG_VIRT_CPU_ACCOUNTING diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c new file mode 100644 index 0000000..2721c3a --- /dev/null +++ b/arch/s390/kernel/machine_kexec.c @@ -0,0 +1,98 @@ +/* + * arch/s390/kernel/machine_kexec.c + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> + * + */ + +/* + * s390_machine_kexec.c - handle the transition of Linux booting another kernel + * on the S390 architecture. + */ + +#include <asm/cio.h> +#include <asm/setup.h> +#include <linux/device.h> +#include <linux/mm.h> +#include <linux/kexec.h> +#include <linux/delay.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/system.h> + +static void kexec_halt_all_cpus(void *); + +typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long); + +const extern unsigned char relocate_kernel[]; +const extern unsigned long long relocate_kernel_len; + +int +machine_kexec_prepare(struct kimage *image) +{ + unsigned long reboot_code_buffer; + + /* We don't support anything but the default image type for now. */ + if (image->type != KEXEC_TYPE_DEFAULT) + return -EINVAL; + + /* Get the destination where the assembler code should be copied to.*/ + reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT; + + /* Then copy it */ + memcpy((void *) reboot_code_buffer, relocate_kernel, + relocate_kernel_len); + return 0; +} + +void +machine_kexec_cleanup(struct kimage *image) +{ +} + +void +machine_shutdown(void) +{ + printk(KERN_INFO "kexec: machine_shutdown called\n"); +} + +NORET_TYPE void +machine_kexec(struct kimage *image) +{ + clear_all_subchannels(); + + /* Disable lowcore protection */ + ctl_clear_bit(0,28); + + on_each_cpu(kexec_halt_all_cpus, image, 0, 0); + for (;;); +} + +static void +kexec_halt_all_cpus(void *kernel_image) +{ + static atomic_t cpuid = ATOMIC_INIT(-1); + int cpu; + struct kimage *image; + relocate_kernel_t data_mover; + + if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid)) + signal_processor(smp_processor_id(), sigp_stop); + + /* Wait for all other cpus to enter stopped state */ + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + while (!smp_cpu_not_running(cpu)) + cpu_relax(); + } + + image = (struct kimage *) kernel_image; + data_mover = (relocate_kernel_t) + (page_to_pfn(image->control_code_page) << PAGE_SHIFT); + + /* Call the moving routine */ + (*data_mover) (&image->head, image->start); +} diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7aea25d..9f3dff6 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code) (void *)(long) smp_processor_id()); } +extern void s390_handle_mcck(void); /* * The idle loop on a S390... */ void default_idle(void) { - psw_t wait_psw; - unsigned long reg; int cpu, rc; local_irq_disable(); @@ -125,38 +124,17 @@ void default_idle(void) cpu_die(); #endif - /* - * Wait for external, I/O or machine check interrupt and - * switch off machine check bit after the wait has ended. - */ - wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT | - PSW_MASK_IO | PSW_MASK_EXT; -#ifndef CONFIG_ARCH_S390X - asm volatile ( - " basr %0,0\n" - "0: la %0,1f-0b(%0)\n" - " st %0,4(%1)\n" - " oi 4(%1),0x80\n" - " lpsw 0(%1)\n" - "1: la %0,2f-1b(%0)\n" - " st %0,4(%1)\n" - " oi 4(%1),0x80\n" - " ni 1(%1),0xf9\n" - " lpsw 0(%1)\n" - "2:" - : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" ); -#else /* CONFIG_ARCH_S390X */ - asm volatile ( - " larl %0,0f\n" - " stg %0,8(%1)\n" - " lpswe 0(%1)\n" - "0: larl %0,1f\n" - " stg %0,8(%1)\n" - " ni 1(%1),0xf9\n" - " lpswe 0(%1)\n" - "1:" - : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" ); -#endif /* CONFIG_ARCH_S390X */ + local_mcck_disable(); + if (test_thread_flag(TIF_MCCK_PENDING)) { + local_mcck_enable(); + local_irq_enable(); + s390_handle_mcck(); + return; + } + + /* Wait for external, I/O or machine check interrupt. */ + __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | + PSW_MASK_IO | PSW_MASK_EXT); } void cpu_idle(void) diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S new file mode 100644 index 0000000..d5e4a62 --- /dev/null +++ b/arch/s390/kernel/relocate_kernel.S @@ -0,0 +1,81 @@ +/* + * arch/s390/kernel/relocate_kernel.S + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> + * + */ + +/* + * moves the new kernel to its destination... + * %r2 = pointer to first kimage_entry_t + * %r3 = start address - where to jump to after the job is done... + * + * %r5 will be used as temp. storage + * %r6 holds the destination address + * %r7 = PAGE_SIZE + * %r8 holds the source address + * %r9 = PAGE_SIZE + * %r10 is a page mask + */ + + .text + .globl relocate_kernel + relocate_kernel: + basr %r13,0 #base address + .base: + spx zero64-.base(%r13) #absolute addressing mode + stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external) + lhi %r10,-1 #preparing the mask + sll %r10,12 #shift it such that it becomes 0xf000 + .top: + lhi %r7,4096 #load PAGE_SIZE in r7 + lhi %r9,4096 #load PAGE_SIZE in r9 + l %r5,0(%r2) #read another word for indirection page + ahi %r2,4 #increment pointer + tml %r5,0x1 #is it a destination page? + je .indir_check #NO, goto "indir_check" + lr %r6,%r5 #r6 = r5 + nr %r6,%r10 #mask it out and... + j .top #...next iteration + .indir_check: + tml %r5,0x2 #is it a indirection page? + je .done_test #NO, goto "done_test" + nr %r5,%r10 #YES, mask out, + lr %r2,%r5 #move it into the right register, + j .top #and read next... + .done_test: + tml %r5,0x4 #is it the done indicator? + je .source_test #NO! Well, then it should be the source indicator... + j .done #ok, lets finish it here... + .source_test: + tml %r5,0x8 #it should be a source indicator... + je .top #NO, ignore it... + lr %r8,%r5 #r8 = r5 + nr %r8,%r10 #masking + 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0 + jo 0b + j .top + .done: + sr %r0,%r0 #clear register r0 + la %r4,load_psw-.base(%r13) #load psw-address into the register + o %r3,4(%r4) #or load address into psw + st %r3,4(%r4) + mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0 + sr %r1,%r1 #clear %r1 + sr %r2,%r2 #clear %r2 + sigp %r1,%r2,0x12 #set cpuid to zero + lpsw 0 #hopefully start new kernel... + + .align 8 + zero64: + .quad 0 + load_psw: + .long 0x00080000,0x80000000 + sys_msk: + .quad 0 + relocate_kernel_end: + .globl relocate_kernel_len + relocate_kernel_len: + .quad relocate_kernel_end - relocate_kernel diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S new file mode 100644 index 0000000..96290cc --- /dev/null +++ b/arch/s390/kernel/relocate_kernel64.S @@ -0,0 +1,82 @@ +/* + * arch/s390/kernel/relocate_kernel64.S + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> + * + */ + +/* + * moves the new kernel to its destination... + * %r2 = pointer to first kimage_entry_t + * %r3 = start address - where to jump to after the job is done... + * + * %r5 will be used as temp. storage + * %r6 holds the destination address + * %r7 = PAGE_SIZE + * %r8 holds the source address + * %r9 = PAGE_SIZE + * + * 0xf000 is a page_mask + */ + + .text + .globl relocate_kernel + relocate_kernel: + basr %r13,0 #base address + .base: + spx zero64-.base(%r13) #absolute addressing mode + stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external) + .top: + lghi %r7,4096 #load PAGE_SIZE in r7 + lghi %r9,4096 #load PAGE_SIZE in r9 + lg %r5,0(%r2) #read another word for indirection page + aghi %r2,8 #increment pointer + tml %r5,0x1 #is it a destination page? + je .indir_check #NO, goto "indir_check" + lgr %r6,%r5 #r6 = r5 + nill %r6,0xf000 #mask it out and... + j .top #...next iteration + .indir_check: + tml %r5,0x2 #is it a indirection page? + je .done_test #NO, goto "done_test" + nill %r5,0xf000 #YES, mask out, + lgr %r2,%r5 #move it into the right register, + j .top #and read next... + .done_test: + tml %r5,0x4 #is it the done indicator? + je .source_test #NO! Well, then it should be the source indicator... + j .done #ok, lets finish it here... + .source_test: + tml %r5,0x8 #it should be a source indicator... + je .top #NO, ignore it... + lgr %r8,%r5 #r8 = r5 + nill %r8,0xf000 #masking + 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0 + jo 0b + j .top + .done: + sgr %r0,%r0 #clear register r0 + la %r4,load_psw-.base(%r13) #load psw-address into the register + o %r3,4(%r4) #or load address into psw + st %r3,4(%r4) + mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0 + sam31 #31 bit mode + sr %r1,%r1 #erase register r1 + sr %r2,%r2 #erase register r2 + sigp %r1,%r2,0x12 #set cpuid to zero + lpsw 0 #hopefully start new kernel... + + .align 8 + zero64: + .quad 0 + load_psw: + .long 0x00080000,0x80000000 + sys_msk: + .quad 0 + relocate_kernel_end: + .globl relocate_kernel_len + relocate_kernel_len: + .quad relocate_kernel_end - relocate_kernel + diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index df83215..b6d740a 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -198,11 +198,11 @@ static void __init conmode_default(void) char *ptr; if (MACHINE_IS_VM) { - __cpcmd("QUERY CONSOLE", query_buffer, 1024); + __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); console_devno = simple_strtoul(query_buffer + 5, NULL, 16); ptr = strstr(query_buffer, "SUBCHANNEL ="); console_irq = simple_strtoul(ptr + 13, NULL, 16); - __cpcmd("QUERY TERM", query_buffer, 1024); + __cpcmd("QUERY TERM", query_buffer, 1024, NULL); ptr = strstr(query_buffer, "CONMODE"); /* * Set the conmode to 3215 so that the device recognition @@ -211,7 +211,7 @@ static void __init conmode_default(void) * 3215 and the 3270 driver will try to access the console * device (3215 as console and 3270 as normal tty). */ - __cpcmd("TERM CONMODE 3215", NULL, 0); + __cpcmd("TERM CONMODE 3215", NULL, 0, NULL); if (ptr == NULL) { #if defined(CONFIG_SCLP_CONSOLE) SET_CONSOLE_SCLP; @@ -414,7 +414,8 @@ setup_lowcore(void) lc->program_new_psw.mask = PSW_KERNEL_BITS; lc->program_new_psw.addr = PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; - lc->mcck_new_psw.mask = PSW_KERNEL_BITS; + lc->mcck_new_psw.mask = + PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; lc->mcck_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; lc->io_new_psw.mask = PSW_KERNEL_BITS; @@ -424,12 +425,18 @@ setup_lowcore(void) lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; lc->async_stack = (unsigned long) __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; -#ifdef CONFIG_CHECK_STACK lc->panic_stack = (unsigned long) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE; -#endif lc->current_task = (unsigned long) init_thread_union.thread_info.task; lc->thread_info = (unsigned long) &init_thread_union; +#ifndef CONFIG_ARCH_S390X + if (MACHINE_HAS_IEEE) { + lc->extended_save_area_addr = (__u32) + __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); + /* enable extended save area */ + ctl_set_bit(14, 29); + } +#endif #ifdef CONFIG_ARCH_S390X if (MACHINE_HAS_DIAG44) lc->diag44_opcode = 0x83000044; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index fdfcf04..642572a 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -284,7 +284,7 @@ static void do_machine_restart(void * __unused) * locks are always held disabled). */ if (MACHINE_IS_VM) - cpcmd ("IPL", NULL, 0); + cpcmd ("IPL", NULL, 0, NULL); else reipl (0x10000 | S390_lowcore.ipl_device); } @@ -313,7 +313,7 @@ static void do_machine_halt(void * __unused) if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) { smp_send_stop(); if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) - cpcmd(vmhalt_cmd, NULL, 0); + cpcmd(vmhalt_cmd, NULL, 0, NULL); signal_processor(smp_processor_id(), sigp_stop_and_store_status); } @@ -332,7 +332,7 @@ static void do_machine_power_off(void * __unused) if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) { smp_send_stop(); if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) - cpcmd(vmpoff_cmd, NULL, 0); + cpcmd(vmpoff_cmd, NULL, 0, NULL); signal_processor(smp_processor_id(), sigp_stop_and_store_status); } @@ -679,12 +679,14 @@ __cpu_disable(void) { unsigned long flags; ec_creg_mask_parms cr_parms; + int cpu = smp_processor_id(); spin_lock_irqsave(&smp_reserve_lock, flags); - if (smp_cpu_reserved[smp_processor_id()] != 0) { + if (smp_cpu_reserved[cpu] != 0) { spin_unlock_irqrestore(&smp_reserve_lock, flags); return -EBUSY; } + cpu_clear(cpu, cpu_online_map); #ifdef CONFIG_PFAULT /* Disable pfault pseudo page faults on this cpu. */ @@ -771,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus) *(lowcore_ptr[i]) = S390_lowcore; lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE); -#ifdef CONFIG_CHECK_STACK stack = __get_free_pages(GFP_KERNEL,0); if (stack == 0ULL) panic("smp_boot_cpus failed to allocate memory\n"); lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE); +#ifndef __s390x__ + if (MACHINE_HAS_IEEE) { + lowcore_ptr[i]->extended_save_area_addr = + (__u32) __get_free_pages(GFP_KERNEL,0); + if (lowcore_ptr[i]->extended_save_area_addr == 0) + panic("smp_boot_cpus failed to " + "allocate memory\n"); + } #endif } +#ifndef __s390x__ + if (MACHINE_HAS_IEEE) + ctl_set_bit(14, 29); /* enable extended save area */ +#endif set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); for_each_cpu(cpu) diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 5159386..a8668af 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -285,7 +285,7 @@ SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper) SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper) SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */ SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper) -NI_SYSCALL /* reserved for kexec */ +SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper) SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper) SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper) SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */ diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index ca34b6f..bc7b7be 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -735,7 +735,7 @@ void __init trap_init(void) &ext_int_pfault); #endif #ifndef CONFIG_ARCH_S390X - cpcmd("SET PAGEX ON", NULL, 0); + cpcmd("SET PAGEX ON", NULL, 0, NULL); #endif } } diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 648deed..c534810 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -576,8 +576,8 @@ segment_save(char *name) segtype_string[seg->range[i].start & 0xff]); } sprintf(cmd2, "SAVESEG %s", name); - cpcmd(cmd1, NULL, 0); - cpcmd(cmd2, NULL, 0); + cpcmd(cmd1, NULL, 0, NULL); + cpcmd(cmd2, NULL, 0, NULL); spin_unlock(&dcss_lock); } diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index cf15b4a..c1b03f7 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -157,9 +157,9 @@ static void daemon_remove(void *data) os_close_file(pri->fd); os_close_file(pri->control); - if(pri->data_addr != NULL) kfree(pri->data_addr); - if(pri->ctl_addr != NULL) kfree(pri->ctl_addr); - if(pri->local_addr != NULL) kfree(pri->local_addr); + kfree(pri->data_addr); + kfree(pri->ctl_addr); + kfree(pri->local_addr); } int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 0f59736..2bb4c4f5 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -602,11 +602,26 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, return n; } -int line_remove(struct line *lines, unsigned int num, char *str) +int line_id(char **str, int *start_out, int *end_out) +{ + char *end; + int n; + + n = simple_strtoul(*str, &end, 0); + if((*end != '\0') || (end == *str)) + return -1; + + *str = end; + *start_out = n; + *end_out = n; + return n; +} + +int line_remove(struct line *lines, unsigned int num, int n) { char config[sizeof("conxxxx=none\0")]; - sprintf(config, "%s=none", str); + sprintf(config, "%d=none", n); return !line_setup(lines, num, config, 0); } diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index d7c7adc..404de41 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -419,8 +419,9 @@ void mconsole_config(struct mc_request *req) void mconsole_remove(struct mc_request *req) { struct mc_device *dev; - char *ptr = req->request.data; - int err; + char *ptr = req->request.data, *err_msg = ""; + char error[256]; + int err, start, end, n; ptr += strlen("remove"); while(isspace(*ptr)) ptr++; @@ -429,8 +430,35 @@ void mconsole_remove(struct mc_request *req) mconsole_reply(req, "Bad remove option", 1, 0); return; } - err = (*dev->remove)(&ptr[strlen(dev->name)]); - mconsole_reply(req, "", err, 0); + + ptr = &ptr[strlen(dev->name)]; + + err = 1; + n = (*dev->id)(&ptr, &start, &end); + if(n < 0){ + err_msg = "Couldn't parse device number"; + goto out; + } + else if((n < start) || (n > end)){ + sprintf(error, "Invalid device number - must be between " + "%d and %d", start, end); + err_msg = error; + goto out; + } + + err = (*dev->remove)(n); + switch(err){ + case -ENODEV: + err_msg = "Device doesn't exist"; + break; + case -EBUSY: + err_msg = "Device is currently open"; + break; + default: + break; + } + out: + mconsole_reply(req, err_msg, err, 0); } #ifdef CONFIG_MAGIC_SYSRQ diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 5388a74..1495007 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -612,25 +612,35 @@ static int net_config(char *str) return(err); } -static int net_remove(char *str) +static int net_id(char **str, int *start_out, int *end_out) +{ + char *end; + int n; + + n = simple_strtoul(*str, &end, 0); + if((*end != '\0') || (end == *str)) + return -1; + + *start_out = n; + *end_out = n; + *str = end; + return n; +} + +static int net_remove(int n) { struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - char *end; - int n; - - n = simple_strtoul(str, &end, 0); - if((*end != '\0') || (end == str)) - return(-1); device = find_device(n); if(device == NULL) - return(0); + return -ENODEV; dev = device->dev; lp = dev->priv; - if(lp->fd > 0) return(-1); + if(lp->fd > 0) + return -EBUSY; if(lp->remove != NULL) (*lp->remove)(&lp->user); unregister_netdev(dev); platform_device_unregister(&device->pdev); @@ -638,13 +648,14 @@ static int net_remove(char *str) list_del(&device->list); kfree(device); free_netdev(dev); - return(0); + return 0; } static struct mc_device net_mc = { .name = "eth", .config = net_config, .get_config = NULL, + .id = net_id, .remove = net_remove, }; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index b32a770..62e04ec 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -49,7 +49,7 @@ static struct chan_opts opts = { static int ssl_config(char *str); static int ssl_get_config(char *dev, char *str, int size, char **error_out); -static int ssl_remove(char *str); +static int ssl_remove(int n); static struct line_driver driver = { .name = "UML serial line", @@ -69,6 +69,7 @@ static struct line_driver driver = { .name = "ssl", .config = ssl_config, .get_config = ssl_get_config, + .id = line_id, .remove = ssl_remove, }, }; @@ -94,10 +95,10 @@ static int ssl_get_config(char *dev, char *str, int size, char **error_out) str, size, error_out)); } -static int ssl_remove(char *str) +static int ssl_remove(int n) { - return(line_remove(serial_lines, - sizeof(serial_lines)/sizeof(serial_lines[0]), str)); + return line_remove(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), n); } int ssl_open(struct tty_struct *tty, struct file *filp) diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index afbe1e7..005aa63 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -55,7 +55,7 @@ static struct chan_opts opts = { static int con_config(char *str); static int con_get_config(char *dev, char *str, int size, char **error_out); -static int con_remove(char *str); +static int con_remove(int n); static struct line_driver driver = { .name = "UML console", @@ -75,6 +75,7 @@ static struct line_driver driver = { .name = "con", .config = con_config, .get_config = con_get_config, + .id = line_id, .remove = con_remove, }, }; @@ -99,9 +100,9 @@ static int con_get_config(char *dev, char *str, int size, char **error_out) size, error_out)); } -static int con_remove(char *str) +static int con_remove(int n) { - return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str)); + return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n); } static int con_open(struct tty_struct *tty, struct file *filp) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 2a7f689..344b24d 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -754,24 +754,34 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out) return(len); } -static int ubd_remove(char *str) +static int ubd_id(char **str, int *start_out, int *end_out) +{ + int n; + + n = parse_unit(str); + *start_out = 0; + *end_out = MAX_DEV - 1; + return n; +} + +static int ubd_remove(int n) { struct ubd *dev; - int n, err = -ENODEV; + int err = -ENODEV; - n = parse_unit(&str); + spin_lock(&ubd_lock); - if((n < 0) || (n >= MAX_DEV)) - return(err); + if(ubd_gendisk[n] == NULL) + goto out; dev = &ubd_dev[n]; - if(dev->count > 0) - return(-EBUSY); /* you cannot remove a open disk */ - err = 0; - spin_lock(&ubd_lock); + if(dev->file == NULL) + goto out; - if(ubd_gendisk[n] == NULL) + /* you cannot remove a open disk */ + err = -EBUSY; + if(dev->count > 0) goto out; del_gendisk(ubd_gendisk[n]); @@ -787,15 +797,16 @@ static int ubd_remove(char *str) platform_device_unregister(&dev->pdev); *dev = ((struct ubd) DEFAULT_UBD); err = 0; - out: - spin_unlock(&ubd_lock); - return(err); +out: + spin_unlock(&ubd_lock); + return err; } static struct mc_device ubd_mc = { .name = "ubd", .config = ubd_config, .get_config = ubd_get_config, + .id = ubd_id, .remove = ubd_remove, }; diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 4c5e92c..5323d22 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -101,7 +101,8 @@ extern void lines_init(struct line *lines, int nlines); extern void close_lines(struct line *lines, int nlines); extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str); -extern int line_remove(struct line *lines, unsigned int sizeof_lines, char *str); +extern int line_id(char **str, int *start_out, int *end_out); +extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n); extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str, int size, char **error_out); diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h index 61c274f..d86ee14 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/include/mconsole_kern.h @@ -20,7 +20,8 @@ struct mc_device { char *name; int (*config)(char *); int (*get_config)(char *, char *, int, char **); - int (*remove)(char *); + int (*id)(char **, int *, int *); + int (*remove)(int); }; #define CONFIG_CHUNK(str, size, current, chunk, end) \ diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h index 6793a2f..f64ef77 100644 --- a/arch/um/include/time_user.h +++ b/arch/um/include/time_user.h @@ -8,11 +8,11 @@ extern void timer(void); extern void switch_timers(int to_real); -extern void set_interval(int timer_type); extern void idle_sleep(int secs); extern void enable_timer(void); extern void disable_timer(void); extern unsigned long time_lock(void); extern void time_unlock(unsigned long); +extern void user_time_init(void); #endif diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c index e59f581..1e1a87f 100644 --- a/arch/um/kernel/main.c +++ b/arch/um/kernel/main.c @@ -69,7 +69,6 @@ static __init void do_uml_initcalls(void) static void last_ditch_exit(int sig) { - kmalloc_ok = 0; signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGHUP, SIG_DFL); diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 157584a..d4036ed 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -96,8 +96,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL, - NULL); + pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, + ¤t->thread.regs, 0, NULL, NULL); if(pid < 0) panic("do_fork failed in kernel_thread, errno = %d", pid); return(pid); @@ -169,7 +169,7 @@ int current_pid(void) void default_idle(void) { - uml_idle_timer(); + CHOOSE_MODE(uml_idle_timer(), (void) 0); atomic_inc(&init_mm.mm_count); current->mm = &init_mm; diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 207f89d..fcec51d 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -38,14 +38,14 @@ static void kill_off_processes(void) void uml_cleanup(void) { - kill_off_processes(); + kmalloc_ok = 0; do_uml_exitcalls(); + kill_off_processes(); } void machine_restart(char * __unused) { - do_uml_exitcalls(); - kill_off_processes(); + uml_cleanup(); CHOOSE_MODE(reboot_tt(), reboot_skas()); } @@ -53,8 +53,7 @@ EXPORT_SYMBOL(machine_restart); void machine_power_off(void) { - do_uml_exitcalls(); - kill_off_processes(); + uml_cleanup(); CHOOSE_MODE(halt_tt(), halt_skas()); } diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index d37d1bf..ff69c4b 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -4,10 +4,10 @@ # obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ - syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \ + syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \ subdir- := util -USER_OBJS := process.o time.o +USER_OBJS := process.o include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h index c1e33bd..bcd26a6 100644 --- a/arch/um/kernel/skas/include/mode-skas.h +++ b/arch/um/kernel/skas/include/mode-skas.h @@ -13,7 +13,6 @@ extern unsigned long exec_fp_regs[]; extern unsigned long exec_fpx_regs[]; extern int have_fpx_regs; -extern void user_time_init_skas(void); extern void sig_handler_common_skas(int sig, void *sc_ptr); extern void halt_skas(void); extern void reboot_skas(void); diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index fc71ef2..0a7b8aa 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -111,8 +111,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, void (*handler)(int); if(current->thread.forking){ - memcpy(&p->thread.regs.regs.skas, - ¤t->thread.regs.regs.skas, + memcpy(&p->thread.regs.regs.skas, ®s->regs.skas, sizeof(p->thread.regs.regs.skas)); REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0); if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; @@ -181,7 +180,6 @@ int start_uml_skas(void) start_userspace(0); init_new_thread_signals(1); - uml_idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; @@ -201,14 +199,3 @@ int thread_pid_skas(struct task_struct *task) #warning Need to look up userspace_pid by cpu return(userspace_pid[0]); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c deleted file mode 100644 index 9809149..0000000 --- a/arch/um/kernel/skas/time.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <sys/signal.h> -#include <sys/time.h> -#include "time_user.h" -#include "process.h" -#include "user.h" - -void user_time_init_skas(void) -{ - if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR) - panic("Couldn't set SIGALRM handler"); - if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index b7a5525..8e1a350 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -31,7 +31,8 @@ long sys_fork(void) long ret; current->thread.forking = 1; - ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), + ¤t->thread.regs, 0, NULL, NULL); current->thread.forking = 0; return(ret); } @@ -41,8 +42,9 @@ long sys_vfork(void) long ret; current->thread.forking = 1; - ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, - NULL); + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, + UPT_SP(¤t->thread.regs.regs), + ¤t->thread.regs, 0, NULL, NULL); current->thread.forking = 0; return(ret); } @@ -162,14 +164,3 @@ int next_syscall_index(int limit) spin_unlock(&syscall_lock); return(ret); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index c40c86a..f829b30 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -33,7 +33,7 @@ void timer(void) timeradd(&xtime, &local_offset, &xtime); } -void set_interval(int timer_type) +static void set_interval(int timer_type) { int usec = 1000000/hz(); struct itimerval interval = ((struct itimerval) { { 0, usec }, @@ -45,12 +45,7 @@ void set_interval(int timer_type) void enable_timer(void) { - int usec = 1000000/hz(); - struct itimerval enable = ((struct itimerval) { { 0, usec }, - { 0, usec }}); - if(setitimer(ITIMER_VIRTUAL, &enable, NULL)) - printk("enable_timer - setitimer failed, errno = %d\n", - errno); + set_interval(ITIMER_VIRTUAL); } void disable_timer(void) @@ -155,13 +150,15 @@ void idle_sleep(int secs) nanosleep(&ts, NULL); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +/* XXX This partly duplicates init_irq_signals */ + +void user_time_init(void) +{ + set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, + SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, + SIGALRM, SIGUSR2, -1); + set_handler(SIGALRM, (__sighandler_t) alarm_handler, + SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, + SIGVTALRM, SIGUSR2, -1); + set_interval(ITIMER_VIRTUAL); +} diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 6516fc5..a8b4ef6 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -162,7 +162,7 @@ int __init timer_init(void) { int err; - CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); + user_time_init(); err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); if(err != 0) printk(KERN_ERR "timer_init : request_irq failed - " diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 3fd2554..6939e5a 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -4,11 +4,11 @@ # obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ - syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ + syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \ uaccess.o uaccess_user.o obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ -USER_OBJS := gdb.o time.o tracer.o +USER_OBJS := gdb.o tracer.o include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c index 19a0ad7..37e22d7 100644 --- a/arch/um/kernel/tt/gdb.c +++ b/arch/um/kernel/tt/gdb.c @@ -153,10 +153,10 @@ void remove_gdb_cb(void *unused) exit_debugger_cb(NULL); } -int gdb_remove(char *unused) +int gdb_remove(int unused) { initial_thread_cb(remove_gdb_cb, NULL); - return(0); + return 0; } void signal_usr1(int sig) diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c index 93fb121..2650638 100644 --- a/arch/um/kernel/tt/gdb_kern.c +++ b/arch/um/kernel/tt/gdb_kern.c @@ -10,7 +10,7 @@ #ifdef CONFIG_MCONSOLE extern int gdb_config(char *str); -extern int gdb_remove(char *unused); +extern int gdb_remove(int n); static struct mc_device gdb_mc = { .name = "gdb", diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h index 8eff674..7384354 100644 --- a/arch/um/kernel/tt/include/debug.h +++ b/arch/um/kernel/tt/include/debug.h @@ -4,8 +4,8 @@ * Licensed under the GPL */ -#ifndef __DEBUG_H -#define __DEBUG_H +#ifndef __UML_TT_DEBUG_H +#define __UML_TT_DEBUG_H extern int debugger_proxy(int status, pid_t pid); extern void child_proxy(pid_t pid, int status); @@ -13,17 +13,6 @@ extern void init_proxy (pid_t pid, int waiting, int status); extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); extern void fake_child_exit(void); extern int gdb_config(char *str); -extern int gdb_remove(char *unused); +extern int gdb_remove(int unused); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h index efe4620..e171e15 100644 --- a/arch/um/kernel/tt/include/mode-tt.h +++ b/arch/um/kernel/tt/include/mode-tt.h @@ -13,7 +13,6 @@ enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; extern int tracing_pid; extern int tracer(int (*init_proc)(void *), void *sp); -extern void user_time_init_tt(void); extern void sig_handler_common_tt(int sig, void *sc); extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); extern void reboot_tt(void); diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 776310f..a189a2b 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -266,10 +266,10 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, } if(current->thread.forking){ - sc_to_sc(UPT_SC(&p->thread.regs.regs), - UPT_SC(¤t->thread.regs.regs)); + sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(®s->regs)); SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0); - if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp; + if(sp != 0) + SC_SP(UPT_SC(&p->thread.regs.regs)) = sp; } p->thread.mode.tt.extern_pid = new_pid; @@ -459,14 +459,3 @@ int is_valid_pid(int pid) read_unlock(&tasklist_lock); return(0); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c deleted file mode 100644 index 8565b71..0000000 --- a/arch/um/kernel/tt/time.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include <sys/time.h> -#include <time_user.h> -#include "process.h" -#include "user.h" - -void user_time_init_tt(void) -{ - if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 03913ca..4efc69a 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -312,7 +312,7 @@ long sys_sigreturn(struct pt_regs regs) unsigned long __user *extramask = frame->extramask; int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) || + if(copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) || copy_from_user(&set.sig[1], extramask, sig_size)) goto segfault; diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c index 335e2d8..83e9be8 100644 --- a/arch/um/sys-i386/syscalls.c +++ b/arch/um/sys-i386/syscalls.c @@ -69,15 +69,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp, { long ret; - /* XXX: normal arch do here this pass, and also pass the regs to - * do_fork, instead of NULL. Currently the arch-independent code - * ignores these values, while the UML code (actually it's - * copy_thread) does the right thing. But this should change, - probably. */ - /*if (!newsp) - newsp = UPT_SP(current->thread.regs);*/ + if (!newsp) + newsp = UPT_SP(¤t->thread.regs.regs); current->thread.forking = 1; - ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); + ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, + child_tid); current->thread.forking = 0; return(ret); } @@ -197,14 +193,3 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act, return ret; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 6f44f40..3259a4d 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -174,26 +174,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp, { long ret; - /* XXX: normal arch do here this pass, and also pass the regs to - * do_fork, instead of NULL. Currently the arch-independent code - * ignores these values, while the UML code (actually it's - * copy_thread) does the right thing. But this should change, - probably. */ - /*if (!newsp) - newsp = UPT_SP(current->thread.regs);*/ + if (!newsp) + newsp = UPT_SP(¤t->thread.regs.regs); current->thread.forking = 1; - ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); + ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, + child_tid); current->thread.forking = 0; return(ret); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index db25975..d09437b 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -207,33 +207,6 @@ config SMP If you don't know what to do here, say N. -config PREEMPT - bool "Preemptible Kernel" - ---help--- - This option reduces the latency of the kernel when reacting to - real-time or interactive events by allowing a low priority process to - be preempted even if it is in kernel mode executing a system call. - This allows applications to run more reliably even when the system is - under load. On contrary it may also break your drivers and add - priority inheritance problems to your system. Don't select it if - you rely on a stable system or have slightly obscure hardware. - It's also not very well tested on x86-64 currently. - You have been warned. - - Say Y here if you are feeling brave and building a kernel for a - desktop, embedded or real-time system. Say N if you are unsure. - -config PREEMPT_BKL - bool "Preempt The Big Kernel Lock" - depends on PREEMPT - default y - help - This option reduces the latency of the kernel by making the - big kernel lock preemptible. - - Say Y here if you are building a kernel for a desktop system. - Say N if you are unsure. - config SCHED_SMT bool "SMT (Hyperthreading) scheduler support" depends on SMP @@ -244,6 +217,8 @@ config SCHED_SMT cost of slightly increased overhead in some places. If unsure say N here. +source "kernel/Kconfig.preempt" + config K8_NUMA bool "K8 NUMA support" select NUMA @@ -313,6 +288,15 @@ config NR_CPUS This is purely to save memory - each supported CPU requires memory in the static kernel configuration. +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + depends on SMP && HOTPLUG && EXPERIMENTAL + help + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu/cpu#. + Say N if you want to disable CPU hotplug. + + config HPET_TIMER bool default y @@ -385,6 +369,34 @@ config X86_MCE_INTEL Additional support for intel specific MCE features such as the thermal monitor. +config PHYSICAL_START + hex "Physical address where the kernel is loaded" if EMBEDDED + default "0x100000" + help + This gives the physical address where the kernel is loaded. + Primarily used in the case of kexec on panic where the + fail safe kernel needs to run at a different address than + the panic-ed kernel. + + Don't change this unless you know what you are doing. + +config KEXEC + bool "kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + config SECCOMP bool "Enable seccomp to safely compute untrusted bytecode" depends on PROC_FS diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 6f90c24..8a73794 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -35,7 +35,7 @@ export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP LDFLAGS := -m elf_x86_64 OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_vmlinux := -e stext +LDFLAGS_vmlinux := CHECKFLAGS += -D__x86_64__ -m64 diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S index 27264db..6f55565 100644 --- a/arch/x86_64/boot/compressed/head.S +++ b/arch/x86_64/boot/compressed/head.S @@ -2,8 +2,6 @@ * linux/boot/head.S * * Copyright (C) 1991, 1992, 1993 Linus Torvalds - * - * $Id: head.S,v 1.3 2001/04/20 00:59:28 ak Exp $ */ /* @@ -21,13 +19,14 @@ */ /* - * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 */ .code32 .text #include <linux/linkage.h> #include <asm/segment.h> +#include <asm/page.h> .code32 .globl startup_32 @@ -77,7 +76,7 @@ startup_32: jnz 3f addl $8,%esp xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 + ljmp $(__KERNEL_CS), $__PHYSICAL_START /* * We come here, if we were loaded high. @@ -103,7 +102,7 @@ startup_32: popl %ecx # lcount popl %edx # high_buffer_start popl %eax # hcount - movl $0x100000,%edi + movl $__PHYSICAL_START,%edi cli # make sure we don't get interrupted ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine @@ -128,7 +127,7 @@ move_routine_start: movsl movl %ebx,%esi # Restore setup pointer xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 + ljmp $(__KERNEL_CS), $__PHYSICAL_START move_routine_end: diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index c8b9216..b38d5b8 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c @@ -11,6 +11,7 @@ #include "miscsetup.h" #include <asm/io.h> +#include <asm/page.h> /* * gzip declarations @@ -92,8 +93,11 @@ static unsigned long output_ptr = 0; static void *malloc(int size); static void free(void *where); +void* memset(void* s, int c, unsigned n); +void* memcpy(void* dest, const void* src, unsigned n); + static void putstr(const char *); - + extern int end; static long free_mem_ptr = (long)&end; static long free_mem_end_ptr; @@ -284,7 +288,7 @@ void setup_normal_output_buffer(void) #else if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory"); #endif - output_data = (char *)0x100000; /* Points to 1M */ + output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */ free_mem_end_ptr = (long)real_mode; } @@ -307,8 +311,8 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv) low_buffer_size = low_buffer_end - LOW_BUFFER_START; high_loaded = 1; free_mem_end_ptr = (long)high_buffer_start; - if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { - high_buffer_start = (uch *)(0x100000 + low_buffer_size); + if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { + high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); mv->hcount = 0; /* say: we need not to move high_buffer */ } else mv->hcount = -1; diff --git a/arch/x86_64/boot/install.sh b/arch/x86_64/boot/install.sh index f17b40d..198af15 100644 --- a/arch/x86_64/boot/install.sh +++ b/arch/x86_64/boot/install.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# arch/i386/boot/install.sh +# arch/x86_64/boot/install.sh # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S index 75d4d2a..ff58b28 100644 --- a/arch/x86_64/boot/setup.S +++ b/arch/x86_64/boot/setup.S @@ -33,7 +33,7 @@ * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * <stiker@northlink.com> * - * Fix to work around buggy BIOSes which dont use carry bit correctly + * Fix to work around buggy BIOSes which don't use carry bit correctly * and/or report extended memory in CX/DX for e801h memory size detection * call. As a result the kernel got wrong figures. The int15/e801h docs * from Ralf Brown interrupt list seem to indicate AX/BX should be used @@ -383,7 +383,7 @@ sse_ok: # a whole bunch of different types, and allows memory holes and # everything. We scan through this memory map and build a list # of the first 32 memory areas, which we return at [E820MAP]. -# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm +# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification. #define SMAP 0x534d4150 @@ -436,7 +436,7 @@ bail820: meme801: stc # fix to work around buggy - xorw %cx,%cx # BIOSes which dont clear/set + xorw %cx,%cx # BIOSes which don't clear/set xorw %dx,%dx # carry on pass/error of # e801h memory size call # or merely pass cx,dx though @@ -733,7 +733,7 @@ flush_instr: # # but we yet haven't reloaded the CS register, so the default size # of the target offset still is 16 bit. -# However, using an operant prefix (0x66), the CPU will properly +# However, using an operand prefix (0x66), the CPU will properly # take our 48 bit far pointer. (INTeL 80386 Programmer's Reference # Manual, Mixing 16-bit and 32-bit code, page 16-6) diff --git a/arch/x86_64/boot/tools/build.c b/arch/x86_64/boot/tools/build.c index c2fa663..18b5bac 100644 --- a/arch/x86_64/boot/tools/build.c +++ b/arch/x86_64/boot/tools/build.c @@ -1,6 +1,4 @@ /* - * $Id: build.c,v 1.3 2001/06/26 15:14:50 pavel Exp $ - * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1997 Martin Mares */ @@ -8,7 +6,8 @@ /* * This file builds a disk-image from three different files: * - * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - bootsect: compatibility mbr which prints an error message if + * someone tries to boot the kernel directly. * - setup: 8086 machine code, sets up system parm * - system: 80386 code for actual system * diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index f3ca0db..cc93542 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -589,7 +589,7 @@ ia32_sys_call_table: .quad compat_sys_mq_timedreceive /* 280 */ .quad compat_sys_mq_notify .quad compat_sys_mq_getsetattr - .quad quiet_ni_syscall /* reserved for kexec */ + .quad compat_sys_kexec_load /* reserved for kexec */ .quad compat_sys_waitid .quad quiet_ni_syscall /* sys_altroot */ .quad sys_add_key diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 5ca4a45..48f9e2c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o \ genapic.o genapic_cluster.o genapic_flat.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_PM) += suspend.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o obj-$(CONFIG_CPU_FREQ) += cpufreq/ diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S index a4c6300..185faa9 100644 --- a/arch/x86_64/kernel/acpi/wakeup.S +++ b/arch/x86_64/kernel/acpi/wakeup.S @@ -67,7 +67,7 @@ wakeup_code: shll $4, %eax addl $(gdta - wakeup_code), %eax movl %eax, gdt_48a +2 - wakeup_code - lgdt %ds:gdt_48a - wakeup_code # load gdt with whatever is + lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is # appropriate movl $1, %eax # protected mode (PE) bit diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index f8e6cc4..375d369 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -133,7 +133,7 @@ void __init connect_bsp_APIC(void) } } -void disconnect_bsp_APIC(void) +void disconnect_bsp_APIC(int virt_wire_setup) { if (pic_mode) { /* @@ -146,6 +146,42 @@ void disconnect_bsp_APIC(void) outb(0x70, 0x22); outb(0x00, 0x23); } + else { + /* Go back to Virtual Wire compatibility mode */ + unsigned long value; + + /* For the spurious interrupt use vector F, and enable it */ + value = apic_read(APIC_SPIV); + value &= ~APIC_VECTOR_MASK; + value |= APIC_SPIV_APIC_ENABLED; + value |= 0xf; + apic_write_around(APIC_SPIV, value); + + if (!virt_wire_setup) { + /* For LVT0 make it edge triggered, active high, external and enabled */ + value = apic_read(APIC_LVT0); + value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED ); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT); + apic_write_around(APIC_LVT0, value); + } + else { + /* Disable LVT0 */ + apic_write_around(APIC_LVT0, APIC_LVT_MASKED); + } + + /* For LVT1 make it edge triggered, active high, nmi and enabled */ + value = apic_read(APIC_LVT1); + value &= ~( + APIC_MODE_MASK | APIC_SEND_PENDING | + APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR | + APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED); + value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING; + value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI); + apic_write_around(APIC_LVT1, value); + } } void disable_local_APIC(void) @@ -285,7 +321,7 @@ void __init init_bsp_APIC(void) apic_write_around(APIC_LVT1, value); } -void __init setup_local_APIC (void) +void __cpuinit setup_local_APIC (void) { unsigned int value, ver, maxlvt; @@ -534,7 +570,7 @@ static struct sys_device device_lapic = { .cls = &lapic_sysclass, }; -static void __init apic_pm_activate(void) +static void __cpuinit apic_pm_activate(void) { apic_pm_state.active = 1; } @@ -774,14 +810,14 @@ void __init setup_boot_APIC_clock (void) local_irq_enable(); } -void __init setup_secondary_APIC_clock(void) +void __cpuinit setup_secondary_APIC_clock(void) { local_irq_disable(); /* FIXME: Do we need this? --RR */ setup_APIC_timer(calibration_result); local_irq_enable(); } -void __init disable_APIC_timer(void) +void __cpuinit disable_APIC_timer(void) { if (using_apic_timer) { unsigned long v; diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c new file mode 100644 index 0000000..d7fa424 --- /dev/null +++ b/arch/x86_64/kernel/crash.c @@ -0,0 +1,35 @@ +/* + * Architecture specific (x86_64) functions for kexec based crash dumps. + * + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * + * Copyright (C) IBM Corporation, 2004. All rights reserved. + * + */ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/smp.h> +#include <linux/irq.h> +#include <linux/reboot.h> +#include <linux/kexec.h> + +#include <asm/processor.h> +#include <asm/hardirq.h> +#include <asm/nmi.h> +#include <asm/hw_irq.h> + +note_buf_t crash_notes[NR_CPUS]; + +void machine_crash_shutdown(struct pt_regs *regs) +{ + /* This function is only called after the system + * has paniced or is otherwise in a critical state. + * The minimum amount of code to allow a kexec'd kernel + * to run successfully needs to happen here. + * + * In practice this means shooting down the other cpus in + * an SMP system. + */ +} diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 7c154df..6ded3a5 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -16,6 +16,7 @@ #include <linux/bootmem.h> #include <linux/ioport.h> #include <linux/string.h> +#include <linux/kexec.h> #include <asm/page.h> #include <asm/e820.h> #include <asm/proto.h> @@ -191,8 +192,6 @@ void __init e820_reserve_resources(void) int i; for (i = 0; i < e820.nr_map; i++) { struct resource *res; - if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) - continue; res = alloc_bootmem_low(sizeof(struct resource)); switch (e820.map[i].type) { case E820_RAM: res->name = "System RAM"; break; @@ -212,6 +211,9 @@ void __init e820_reserve_resources(void) */ request_resource(res, &code_resource); request_resource(res, &data_resource); +#ifdef CONFIG_KEXEC + request_resource(res, &crashk_res); +#endif } } } diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index b4cbbad..2828469 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c @@ -7,6 +7,8 @@ * Hacked for x86-64 by James Cleverdon from i386 architecture code by * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and * James Cleverdon. + * Ashok Raj <ashok.raj@intel.com> + * Removed IPI broadcast shortcut to support CPU hotplug */ #include <linux/config.h> #include <linux/threads.h> @@ -18,6 +20,46 @@ #include <asm/smp.h> #include <asm/ipi.h> +/* + * The following permit choosing broadcast IPI shortcut v.s sending IPI only + * to online cpus via the send_IPI_mask varient. + * The mask version is my preferred option, since it eliminates a lot of + * other extra code that would need to be written to cleanup intrs sent + * to a CPU while offline. + * + * Sending broadcast introduces lots of trouble in CPU hotplug situations. + * These IPI's are delivered to cpu's irrespective of their offline status + * and could pickup stale intr data when these CPUS are turned online. + * + * Not using broadcast is a cleaner approach IMO, but Andi Kleen disagrees with + * the idea of not using broadcast IPI's anymore. Hence the run time check + * is introduced, on his request so we can choose an alternate mechanism. + * + * Initial wacky performance tests that collect cycle counts show + * no increase in using mask v.s broadcast version. In fact they seem + * identical in terms of cycle counts. + * + * if we need to use broadcast, we need to do the following. + * + * cli; + * hold call_lock; + * clear any pending IPI, just ack and clear all pending intr + * set cpu_online_map; + * release call_lock; + * sti; + * + * The complicated dummy irq processing shown above is not required if + * we didnt sent IPI's to wrong CPU's in the first place. + * + * - Ashok Raj <ashok.raj@intel.com> + */ +#ifdef CONFIG_HOTPLUG_CPU +#define DEFAULT_SEND_IPI (1) +#else +#define DEFAULT_SEND_IPI (0) +#endif + +static int no_broadcast=DEFAULT_SEND_IPI; static cpumask_t flat_target_cpus(void) { @@ -45,22 +87,6 @@ static void flat_init_apic_ldr(void) apic_write_around(APIC_LDR, val); } -static void flat_send_IPI_allbutself(int vector) -{ - /* - * if there are no other CPUs in the system then - * we get an APIC send error if we try to broadcast. - * thus we have to avoid sending IPIs in this case. - */ - if (num_online_cpus() > 1) - __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL); -} - -static void flat_send_IPI_all(int vector) -{ - __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); -} - static void flat_send_IPI_mask(cpumask_t cpumask, int vector) { unsigned long mask = cpus_addr(cpumask)[0]; @@ -93,6 +119,39 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) local_irq_restore(flags); } +static inline void __local_flat_send_IPI_allbutself(int vector) +{ + if (no_broadcast) { + cpumask_t mask = cpu_online_map; + int this_cpu = get_cpu(); + + cpu_clear(this_cpu, mask); + flat_send_IPI_mask(mask, vector); + put_cpu(); + } + else + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL); +} + +static inline void __local_flat_send_IPI_all(int vector) +{ + if (no_broadcast) + flat_send_IPI_mask(cpu_online_map, vector); + else + __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); +} + +static void flat_send_IPI_allbutself(int vector) +{ + if (((num_online_cpus()) - 1) >= 1) + __local_flat_send_IPI_allbutself(vector); +} + +static void flat_send_IPI_all(int vector) +{ + __local_flat_send_IPI_all(vector); +} + static int flat_apic_id_registered(void) { return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map); @@ -111,6 +170,16 @@ static unsigned int phys_pkg_id(int index_msb) return ((ebx >> 24) & 0xFF) >> index_msb; } +static __init int no_ipi_broadcast(char *str) +{ + get_option(&str, &no_broadcast); + printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" : + "IPI Broadcast"); + return 1; +} + +__setup("no_ipi_broadcast", no_ipi_broadcast); + struct genapic apic_flat = { .name = "flat", .int_delivery_mode = dest_LowestPrio, @@ -125,3 +194,12 @@ struct genapic apic_flat = { .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, .phys_pkg_id = phys_pkg_id, }; + +static int __init print_ipi_mode(void) +{ + printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" : + "Shortcut"); + return 0; +} + +late_initcall(print_ipi_mode); diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S index 9bd2e7a..8d765aa 100644 --- a/arch/x86_64/kernel/head.S +++ b/arch/x86_64/kernel/head.S @@ -248,23 +248,23 @@ ENTRY(_stext) */ .org 0x1000 ENTRY(init_level4_pgt) - .quad 0x0000000000102007 /* -> level3_ident_pgt */ + .quad 0x0000000000002007 + __PHYSICAL_START /* -> level3_ident_pgt */ .fill 255,8,0 - .quad 0x000000000010a007 + .quad 0x000000000000a007 + __PHYSICAL_START .fill 254,8,0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad 0x0000000000103007 /* -> level3_kernel_pgt */ + .quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */ .org 0x2000 ENTRY(level3_ident_pgt) - .quad 0x0000000000104007 + .quad 0x0000000000004007 + __PHYSICAL_START .fill 511,8,0 .org 0x3000 ENTRY(level3_kernel_pgt) .fill 510,8,0 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */ - .quad 0x0000000000105007 /* -> level2_kernel_pgt */ + .quad 0x0000000000005007 + __PHYSICAL_START /* -> level2_kernel_pgt */ .fill 1,8,0 .org 0x4000 @@ -337,17 +337,17 @@ ENTRY(empty_bad_pmd_table) .org 0xa000 ENTRY(level3_physmem_pgt) - .quad 0x0000000000105007 /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */ + .quad 0x0000000000005007 + __PHYSICAL_START /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */ .org 0xb000 #ifdef CONFIG_ACPI_SLEEP ENTRY(wakeup_level4_pgt) - .quad 0x0000000000102007 /* -> level3_ident_pgt */ + .quad 0x0000000000002007 + __PHYSICAL_START /* -> level3_ident_pgt */ .fill 255,8,0 - .quad 0x000000000010a007 + .quad 0x000000000000a007 + __PHYSICAL_START .fill 254,8,0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ - .quad 0x0000000000103007 /* -> level3_kernel_pgt */ + .quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */ #endif .data diff --git a/arch/x86_64/kernel/i387.c b/arch/x86_64/kernel/i387.c index ba139ca..d9b22b6 100644 --- a/arch/x86_64/kernel/i387.c +++ b/arch/x86_64/kernel/i387.c @@ -42,7 +42,7 @@ void mxcsr_feature_mask_init(void) * Called at bootup to set up the initial FPU state that is later cloned * into all processes. */ -void __init fpu_init(void) +void __cpuinit fpu_init(void) { unsigned long oldcr0 = read_cr0(); extern void __bad_fxsave_alignment(void); diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 19eafa0..a891690 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -414,10 +414,22 @@ static int i8259A_suspend(struct sys_device *dev, pm_message_t state) return 0; } +static int i8259A_shutdown(struct sys_device *dev) +{ + /* Put the i8259A into a quiescent state that + * the kernel initialization code can get it + * out of. + */ + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-1 */ + return 0; +} + static struct sysdev_class i8259_sysdev_class = { set_kset_name("i8259"), .suspend = i8259A_suspend, .resume = i8259A_resume, + .shutdown = i8259A_shutdown, }; static struct sys_device device_i8259A = { diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index afd87e6..157190d 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -330,7 +330,7 @@ static int find_irq_entry(int apic, int pin, int type) /* * Find the pin to which IRQ[irq] (ISA) is connected */ -static int __init find_isa_irq_pin(int irq, int type) +static int find_isa_irq_pin(int irq, int type) { int i; @@ -1132,12 +1132,44 @@ static void __init enable_IO_APIC(void) */ void disable_IO_APIC(void) { + int pin; /* * Clear the IO-APIC before rebooting: */ clear_IO_APIC(); - disconnect_bsp_APIC(); + /* + * If the i82559 is routed through an IOAPIC + * Put that IOAPIC in virtual wire mode + * so legacy interrups can be delivered. + */ + pin = find_isa_irq_pin(0, mp_ExtINT); + if (pin != -1) { + struct IO_APIC_route_entry entry; + unsigned long flags; + + memset(&entry, 0, sizeof(entry)); + entry.mask = 0; /* Enabled */ + entry.trigger = 0; /* Edge */ + entry.irr = 0; + entry.polarity = 0; /* High */ + entry.delivery_status = 0; + entry.dest_mode = 0; /* Physical */ + entry.delivery_mode = 7; /* ExtInt */ + entry.vector = 0; + entry.dest.physical.physical_dest = 0; + + + /* + * Add it to the IO-APIC irq-routing table: + */ + spin_lock_irqsave(&ioapic_lock, flags); + io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + + disconnect_bsp_APIC(pin != -1); } /* diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 62b112e..cc3fb85 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -14,6 +14,7 @@ #include <linux/interrupt.h> #include <linux/seq_file.h> #include <linux/module.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/io_apic.h> @@ -106,3 +107,31 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) return 1; } +#ifdef CONFIG_HOTPLUG_CPU +void fixup_irqs(cpumask_t map) +{ + unsigned int irq; + static int warned; + + for (irq = 0; irq < NR_IRQS; irq++) { + cpumask_t mask; + if (irq == 2) + continue; + + cpus_and(mask, irq_affinity[irq], map); + if (any_online_cpu(mask) == NR_CPUS) { + printk("Breaking affinity for irq %i\n", irq); + mask = map; + } + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + else if (irq_desc[irq].action && !(warned++)) + printk("Cannot set affinity for irq %i\n", irq); + } + + /* That doesn't seem sufficient. Give it 1ms. */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); +} +#endif diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c new file mode 100644 index 0000000..60d1eff --- /dev/null +++ b/arch/x86_64/kernel/machine_kexec.c @@ -0,0 +1,250 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/mm.h> +#include <linux/kexec.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/reboot.h> +#include <asm/pda.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> +#include <asm/mmu_context.h> +#include <asm/io.h> +#include <asm/apic.h> +#include <asm/cpufeature.h> +#include <asm/hw_irq.h> + +#define LEVEL0_SIZE (1UL << 12UL) +#define LEVEL1_SIZE (1UL << 21UL) +#define LEVEL2_SIZE (1UL << 30UL) +#define LEVEL3_SIZE (1UL << 39UL) +#define LEVEL4_SIZE (1UL << 48UL) + +#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE) +#define L2_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define L3_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) + +static void init_level2_page(u64 *level2p, unsigned long addr) +{ + unsigned long end_addr; + + addr &= PAGE_MASK; + end_addr = addr + LEVEL2_SIZE; + while (addr < end_addr) { + *(level2p++) = addr | L1_ATTR; + addr += LEVEL1_SIZE; + } +} + +static int init_level3_page(struct kimage *image, u64 *level3p, + unsigned long addr, unsigned long last_addr) +{ + unsigned long end_addr; + int result; + + result = 0; + addr &= PAGE_MASK; + end_addr = addr + LEVEL3_SIZE; + while ((addr < last_addr) && (addr < end_addr)) { + struct page *page; + u64 *level2p; + + page = kimage_alloc_control_pages(image, 0); + if (!page) { + result = -ENOMEM; + goto out; + } + level2p = (u64 *)page_address(page); + init_level2_page(level2p, addr); + *(level3p++) = __pa(level2p) | L2_ATTR; + addr += LEVEL2_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { + *(level3p++) = 0; + addr += LEVEL2_SIZE; + } +out: + return result; +} + + +static int init_level4_page(struct kimage *image, u64 *level4p, + unsigned long addr, unsigned long last_addr) +{ + unsigned long end_addr; + int result; + + result = 0; + addr &= PAGE_MASK; + end_addr = addr + LEVEL4_SIZE; + while ((addr < last_addr) && (addr < end_addr)) { + struct page *page; + u64 *level3p; + + page = kimage_alloc_control_pages(image, 0); + if (!page) { + result = -ENOMEM; + goto out; + } + level3p = (u64 *)page_address(page); + result = init_level3_page(image, level3p, addr, last_addr); + if (result) { + goto out; + } + *(level4p++) = __pa(level3p) | L3_ATTR; + addr += LEVEL3_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { + *(level4p++) = 0; + addr += LEVEL3_SIZE; + } +out: + return result; +} + + +static int init_pgtable(struct kimage *image, unsigned long start_pgtable) +{ + u64 *level4p; + level4p = (u64 *)__va(start_pgtable); + return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); +} + +static void set_idt(void *newidt, u16 limit) +{ + unsigned char curidt[10]; + + /* x86-64 supports unaliged loads & stores */ + (*(u16 *)(curidt)) = limit; + (*(u64 *)(curidt +2)) = (unsigned long)(newidt); + + __asm__ __volatile__ ( + "lidt %0\n" + : "=m" (curidt) + ); +}; + + +static void set_gdt(void *newgdt, u16 limit) +{ + unsigned char curgdt[10]; + + /* x86-64 supports unaligned loads & stores */ + (*(u16 *)(curgdt)) = limit; + (*(u64 *)(curgdt +2)) = (unsigned long)(newgdt); + + __asm__ __volatile__ ( + "lgdt %0\n" + : "=m" (curgdt) + ); +}; + +static void load_segments(void) +{ + __asm__ __volatile__ ( + "\tmovl $"STR(__KERNEL_DS)",%eax\n" + "\tmovl %eax,%ds\n" + "\tmovl %eax,%es\n" + "\tmovl %eax,%ss\n" + "\tmovl %eax,%fs\n" + "\tmovl %eax,%gs\n" + ); +#undef STR +#undef __STR +} + +typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page, + unsigned long control_code_buffer, + unsigned long start_address, + unsigned long pgtable) ATTRIB_NORET; + +const extern unsigned char relocate_new_kernel[]; +const extern unsigned long relocate_new_kernel_size; + +int machine_kexec_prepare(struct kimage *image) +{ + unsigned long start_pgtable, control_code_buffer; + int result; + + /* Calculate the offsets */ + start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; + control_code_buffer = start_pgtable + 4096UL; + + /* Setup the identity mapped 64bit page table */ + result = init_pgtable(image, start_pgtable); + if (result) + return result; + + /* Place the code in the reboot code buffer */ + memcpy(__va(control_code_buffer), relocate_new_kernel, + relocate_new_kernel_size); + + return 0; +} + +void machine_kexec_cleanup(struct kimage *image) +{ + return; +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) +{ + unsigned long page_list; + unsigned long control_code_buffer; + unsigned long start_pgtable; + relocate_new_kernel_t rnk; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + /* Calculate the offsets */ + page_list = image->head; + start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; + control_code_buffer = start_pgtable + 4096UL; + + /* Set the low half of the page table to my identity mapped + * page table for kexec. Leave the high half pointing at the + * kernel pages. Don't bother to flush the global pages + * as that will happen when I fully switch to my identity mapped + * page table anyway. + */ + memcpy(__va(read_cr3()), __va(start_pgtable), PAGE_SIZE/2); + __flush_tlb(); + + + /* The segment registers are funny things, they are + * automatically loaded from a table, in memory wherever you + * set them to a specific selector, but this table is never + * accessed again unless you set the segment to a different selector. + * + * The more common model are caches where the behide + * the scenes work is done, but is also dropped at arbitrary + * times. + * + * I take advantage of this here by force loading the + * segments, before I zap the gdt with an invalid value. + */ + load_segments(); + /* The gdt & idt are now invalid. + * If you want to load them you must set up your own idt & gdt. + */ + set_gdt(phys_to_virt(0),0); + set_idt(phys_to_virt(0),0); + /* now call it */ + rnk = (relocate_new_kernel_t) control_code_buffer; + (*rnk)(page_list, control_code_buffer, image->start, start_pgtable); +} diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 3a89d73..21e7062 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -327,7 +327,7 @@ static void mce_init(void *dummy) } /* Add per CPU specific workarounds here */ -static void __init mce_cpu_quirks(struct cpuinfo_x86 *c) +static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c) { /* This should be disabled by the BIOS, but isn't always */ if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) { @@ -337,7 +337,7 @@ static void __init mce_cpu_quirks(struct cpuinfo_x86 *c) } } -static void __init mce_cpu_features(struct cpuinfo_x86 *c) +static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c) { switch (c->x86_vendor) { case X86_VENDOR_INTEL: @@ -352,7 +352,7 @@ static void __init mce_cpu_features(struct cpuinfo_x86 *c) * Called for each booted CPU to set up machine checks. * Must be called with preempt off. */ -void __init mcheck_init(struct cpuinfo_x86 *c) +void __cpuinit mcheck_init(struct cpuinfo_x86 *c) { static cpumask_t mce_cpus __initdata = CPU_MASK_NONE; @@ -411,7 +411,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff memset(mcelog.entry, 0, next * sizeof(struct mce)); mcelog.next = 0; - synchronize_kernel(); + synchronize_sched(); /* Collect entries that were still getting written before the synchronize. */ @@ -542,7 +542,7 @@ ACCESSOR(bank4ctl,bank[4],mce_restart()) ACCESSOR(tolerant,tolerant,) ACCESSOR(check_interval,check_interval,mce_restart()) -static __init int mce_init_device(void) +static __cpuinit int mce_init_device(void) { int err; if (!mce_available(&boot_cpu_data)) diff --git a/arch/x86_64/kernel/mce_intel.c b/arch/x86_64/kernel/mce_intel.c index 4db9a64..0be0a79 100644 --- a/arch/x86_64/kernel/mce_intel.c +++ b/arch/x86_64/kernel/mce_intel.c @@ -42,7 +42,7 @@ done: irq_exit(); } -static void __init intel_init_thermal(struct cpuinfo_x86 *c) +static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c) { u32 l, h; int tm2 = 0; @@ -93,7 +93,7 @@ static void __init intel_init_thermal(struct cpuinfo_x86 *c) return; } -void __init mce_intel_feature_init(struct cpuinfo_x86 *c) +void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c) { intel_init_thermal(c); } diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 31c0f2e..4e44d6e 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -98,7 +98,7 @@ static unsigned int nmi_p4_cccr_val; (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) -static __init inline int nmi_known_cpu(void) +static __cpuinit inline int nmi_known_cpu(void) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: @@ -110,7 +110,7 @@ static __init inline int nmi_known_cpu(void) } /* Run after command line and cpu_init init, but before all other checks */ -void __init nmi_watchdog_default(void) +void __cpuinit nmi_watchdog_default(void) { if (nmi_watchdog != NMI_DEFAULT) return; diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index e59d1f9..1d91271 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -8,7 +8,8 @@ * * X86-64 port * Andi Kleen. - * + * + * CPU hotplug support - ashok.raj@intel.com * $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $ */ @@ -18,6 +19,7 @@ #include <stdarg.h> +#include <linux/cpu.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -154,6 +156,29 @@ void cpu_idle_wait(void) } EXPORT_SYMBOL_GPL(cpu_idle_wait); +#ifdef CONFIG_HOTPLUG_CPU +DECLARE_PER_CPU(int, cpu_state); + +#include <asm/nmi.h> +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void play_dead(void) +{ + idle_task_exit(); + wbinvd(); + mb(); + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + while (1) + safe_halt(); +} +#else +static inline void play_dead(void) +{ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + /* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a @@ -174,6 +199,8 @@ void cpu_idle (void) idle = pm_idle; if (!idle) idle = default_idle; + if (cpu_is_offline(smp_processor_id())) + play_dead(); idle(); } @@ -204,7 +231,7 @@ static void mwait_idle(void) } } -void __init select_idle_routine(const struct cpuinfo_x86 *c) +void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) { static int printed; if (cpu_has(c, X86_FEATURE_MWAIT)) { diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c index be4b36f..57e71db 100644 --- a/arch/x86_64/kernel/reboot.c +++ b/arch/x86_64/kernel/reboot.c @@ -66,41 +66,47 @@ static int __init reboot_setup(char *str) __setup("reboot=", reboot_setup); -#ifdef CONFIG_SMP -static void smp_halt(void) +static inline void kb_wait(void) { - int cpuid = safe_smp_processor_id(); - static int first_entry = 1; + int i; - if (reboot_force) - return; + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} - if (first_entry) { - first_entry = 0; - smp_call_function((void *)machine_restart, NULL, 1, 0); - } - - smp_stop_cpu(); +void machine_shutdown(void) +{ + /* Stop the cpus and apics */ +#ifdef CONFIG_SMP + int reboot_cpu_id; - /* AP calling this. Just halt */ - if (cpuid != boot_cpu_id) { - for (;;) - asm("hlt"); + /* The boot cpu is always logical cpu 0 */ + reboot_cpu_id = 0; + + /* Make certain the cpu I'm about to reboot on is online */ + if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { + reboot_cpu_id = smp_processor_id(); } - /* Wait for all other CPUs to have run smp_stop_cpu */ - while (!cpus_empty(cpu_online_map)) - rep_nop(); -} + /* Make certain I only run on the appropriate processor */ + set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); + + /* O.K Now that I'm on the appropriate processor, + * stop all of the others. + */ + smp_send_stop(); #endif -static inline void kb_wait(void) -{ - int i; + local_irq_disable(); - for (i=0; i<0x10000; i++) - if ((inb_p(0x64) & 0x02) == 0) - break; +#ifndef CONFIG_SMP + disable_local_APIC(); +#endif + + disable_IO_APIC(); + + local_irq_enable(); } void machine_restart(char * __unused) @@ -109,9 +115,7 @@ void machine_restart(char * __unused) printk("machine restart\n"); -#ifdef CONFIG_SMP - smp_halt(); -#endif + machine_shutdown(); if (!reboot_force) { local_irq_disable(); diff --git a/arch/x86_64/kernel/relocate_kernel.S b/arch/x86_64/kernel/relocate_kernel.S new file mode 100644 index 0000000..d24fa9b --- /dev/null +++ b/arch/x86_64/kernel/relocate_kernel.S @@ -0,0 +1,143 @@ +/* + * relocate_kernel.S - put the kernel image in place to boot + * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com> + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/linkage.h> + + /* + * Must be relocatable PIC code callable as a C function, that once + * it starts can not use the previous processes stack. + */ + .globl relocate_new_kernel + .code64 +relocate_new_kernel: + /* %rdi page_list + * %rsi reboot_code_buffer + * %rdx start address + * %rcx page_table + * %r8 arg5 + * %r9 arg6 + */ + + /* zero out flags, and disable interrupts */ + pushq $0 + popfq + + /* set a new stack at the bottom of our page... */ + lea 4096(%rsi), %rsp + + /* store the parameters back on the stack */ + pushq %rdx /* store the start address */ + + /* Set cr0 to a known state: + * 31 1 == Paging enabled + * 18 0 == Alignment check disabled + * 16 0 == Write protect disabled + * 3 0 == No task switch + * 2 0 == Don't do FP software emulation. + * 0 1 == Proctected mode enabled + */ + movq %cr0, %rax + andq $~((1<<18)|(1<<16)|(1<<3)|(1<<2)), %rax + orl $((1<<31)|(1<<0)), %eax + movq %rax, %cr0 + + /* Set cr4 to a known state: + * 10 0 == xmm exceptions disabled + * 9 0 == xmm registers instructions disabled + * 8 0 == performance monitoring counter disabled + * 7 0 == page global disabled + * 6 0 == machine check exceptions disabled + * 5 1 == physical address extension enabled + * 4 0 == page size extensions disabled + * 3 0 == Debug extensions disabled + * 2 0 == Time stamp disable (disabled) + * 1 0 == Protected mode virtual interrupts disabled + * 0 0 == VME disabled + */ + + movq $((1<<5)), %rax + movq %rax, %cr4 + + jmp 1f +1: + + /* Switch to the identity mapped page tables, + * and flush the TLB. + */ + movq %rcx, %cr3 + + /* Do the copies */ + movq %rdi, %rcx /* Put the page_list in %rcx */ + xorq %rdi, %rdi + xorq %rsi, %rsi + jmp 1f + +0: /* top, read another word for the indirection page */ + + movq (%rbx), %rcx + addq $8, %rbx +1: + testq $0x1, %rcx /* is it a destination page? */ + jz 2f + movq %rcx, %rdi + andq $0xfffffffffffff000, %rdi + jmp 0b +2: + testq $0x2, %rcx /* is it an indirection page? */ + jz 2f + movq %rcx, %rbx + andq $0xfffffffffffff000, %rbx + jmp 0b +2: + testq $0x4, %rcx /* is it the done indicator? */ + jz 2f + jmp 3f +2: + testq $0x8, %rcx /* is it the source indicator? */ + jz 0b /* Ignore it otherwise */ + movq %rcx, %rsi /* For ever source page do a copy */ + andq $0xfffffffffffff000, %rsi + + movq $512, %rcx + rep ; movsq + jmp 0b +3: + + /* To be certain of avoiding problems with self-modifying code + * I need to execute a serializing instruction here. + * So I flush the TLB by reloading %cr3 here, it's handy, + * and not processor dependent. + */ + movq %cr3, %rax + movq %rax, %cr3 + + /* set all of the registers to known values */ + /* leave %rsp alone */ + + xorq %rax, %rax + xorq %rbx, %rbx + xorq %rcx, %rcx + xorq %rdx, %rdx + xorq %rsi, %rsi + xorq %rdi, %rdi + xorq %rbp, %rbp + xorq %r8, %r8 + xorq %r9, %r9 + xorq %r10, %r9 + xorq %r11, %r11 + xorq %r12, %r12 + xorq %r13, %r13 + xorq %r14, %r14 + xorq %r15, %r15 + + ret +relocate_new_kernel_end: + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .quad relocate_new_kernel_end - relocate_new_kernel diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 000015d..b02d921 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -41,6 +41,7 @@ #include <linux/kallsyms.h> #include <linux/edd.h> #include <linux/mmzone.h> +#include <linux/kexec.h> #include <asm/mtrr.h> #include <asm/uaccess.h> @@ -367,6 +368,27 @@ static __init void parse_cmdline_early (char ** cmdline_p) if (!memcmp(from, "noexec=", 7)) nonx_setup(from + 7); +#ifdef CONFIG_KEXEC + /* crashkernel=size@addr specifies the location to reserve for + * a crash kernel. By reserving this memory we guarantee + * that linux never set's it up as a DMA target. + * Useful for holding code to do something appropriate + * after a kernel panic. + */ + else if (!memcmp(from, "crashkernel=", 12)) { + unsigned long size, base; + size = memparse(from+12, &from); + if (*from == '@') { + base = memparse(from+1, &from); + /* FIXME: Do I want a sanity check + * to validate the memory range? + */ + crashk_res.start = base; + crashk_res.end = base + size - 1; + } + } +#endif + next_char: c = *(from++); if (!c) @@ -625,6 +647,13 @@ void __init setup_arch(char **cmdline_p) #endif sparse_init(); + +#ifdef CONFIG_KEXEC + if (crashk_res.start != crashk_res.end) { + reserve_bootmem(crashk_res.start, + crashk_res.end - crashk_res.start + 1); + } +#endif paging_init(); check_ioapic(); @@ -676,7 +705,7 @@ void __init setup_arch(char **cmdline_p) #endif } -static int __init get_model_name(struct cpuinfo_x86 *c) +static int __cpuinit get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; @@ -692,7 +721,7 @@ static int __init get_model_name(struct cpuinfo_x86 *c) } -static void __init display_cacheinfo(struct cpuinfo_x86 *c) +static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c) { unsigned int n, dummy, eax, ebx, ecx, edx; @@ -803,7 +832,7 @@ static int __init init_amd(struct cpuinfo_x86 *c) return r; } -static void __init detect_ht(struct cpuinfo_x86 *c) +static void __cpuinit detect_ht(struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP u32 eax, ebx, ecx, edx; @@ -864,7 +893,7 @@ static void __init detect_ht(struct cpuinfo_x86 *c) /* * find out the number of processor cores on the die */ -static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c) +static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c) { unsigned int eax; @@ -882,7 +911,7 @@ static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c) return 1; } -static void __init init_intel(struct cpuinfo_x86 *c) +static void __cpuinit init_intel(struct cpuinfo_x86 *c) { /* Cache sizes */ unsigned n; @@ -902,7 +931,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) c->x86_num_cores = intel_num_cpu_cores(c); } -void __init get_cpu_vendor(struct cpuinfo_x86 *c) +void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -923,7 +952,7 @@ struct cpu_model_info { /* Do some early cpuid on the boot CPU to get some parameter that are needed before check_bugs. Everything advanced is in identify_cpu below. */ -void __init early_identify_cpu(struct cpuinfo_x86 *c) +void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) { u32 tfms; @@ -977,7 +1006,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c) /* * This does the hard work of actually picking apart the CPU stuff... */ -void __init identify_cpu(struct cpuinfo_x86 *c) +void __cpuinit identify_cpu(struct cpuinfo_x86 *c) { int i; u32 xlvl; @@ -1054,7 +1083,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c) } -void __init print_cpu_info(struct cpuinfo_x86 *c) +void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) { if (c->x86_model_id[0]) printk("%s", c->x86_model_id); diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index 678b7ac..f2b9c6b 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -29,7 +29,7 @@ char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,}; -cpumask_t cpu_initialized __initdata = CPU_MASK_NONE; +cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned; @@ -171,7 +171,7 @@ void syscall_init(void) wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); } -void __init check_efer(void) +void __cpuinit check_efer(void) { unsigned long efer; @@ -188,7 +188,7 @@ void __init check_efer(void) * 'CPU state barrier', nothing should get across. * A lot of state is already set up in PDA init. */ -void __init cpu_init (void) +void __cpuinit cpu_init (void) { #ifdef CONFIG_SMP int cpu = stack_smp_processor_id(); diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 98b7ba9..98590a9 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -425,7 +425,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!user_mode(regs)) return 1; - if (try_to_freeze(0)) + if (try_to_freeze()) goto no_signal; if (!oldset) diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c index 1e379ed..ccae392 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -283,6 +283,16 @@ struct call_data_struct { static struct call_data_struct * call_data; +void lock_ipi_call_lock(void) +{ + spin_lock_irq(&call_lock); +} + +void unlock_ipi_call_lock(void) +{ + spin_unlock_irq(&call_lock); +} + /* * this function sends a 'generic call function' IPI to all other CPUs * in the system. diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index f1ec0f3..b969ee1 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -34,6 +34,7 @@ * Andi Kleen : Converted to new state machine. * Various cleanups. * Probably mostly hotplug CPU ready now. + * Ashok Raj : CPU hotplug support */ @@ -58,11 +59,6 @@ #include <asm/proto.h> #include <asm/nmi.h> -/* Change for real CPU hotplug. Note other files need to be fixed - first too. */ -#define __cpuinit __init -#define __cpuinitdata __initdata - /* Number of siblings per CPU package */ int smp_num_siblings = 1; /* Package ID of each logical CPU */ @@ -103,6 +99,37 @@ EXPORT_SYMBOL(cpu_core_map); extern unsigned char trampoline_data[]; extern unsigned char trampoline_end[]; +/* State of each CPU */ +DEFINE_PER_CPU(int, cpu_state) = { 0 }; + +/* + * Store all idle threads, this can be reused instead of creating + * a new thread. Also avoids complicated thread destroy functionality + * for idle threads. + */ +struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ; + +#define get_idle_for_cpu(x) (idle_thread_array[(x)]) +#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p)) + +/* + * cpu_possible_map should be static, it cannot change as cpu's + * are onlined, or offlined. The reason is per-cpu data-structures + * are allocated by some modules at init time, and dont expect to + * do this dynamically on cpu arrival/departure. + * cpu_present_map on the other hand can change dynamically. + * In case when cpu_hotplug is not compiled, then we resort to current + * behaviour, which is cpu_possible == cpu_present. + * If cpu-hotplug is supported, then we need to preallocate for all + * those NR_CPUS, hence cpu_possible_map represents entire NR_CPUS range. + * - Ashok Raj + */ +#ifdef CONFIG_HOTPLUG_CPU +#define fixup_cpu_possible_map(x) cpu_set((x), cpu_possible_map) +#else +#define fixup_cpu_possible_map(x) +#endif + /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller @@ -418,6 +445,33 @@ void __cpuinit smp_callin(void) cpu_set(cpuid, cpu_callin_map); } +static inline void set_cpu_sibling_map(int cpu) +{ + int i; + + if (smp_num_siblings > 1) { + for_each_cpu(i) { + if (cpu_core_id[cpu] == cpu_core_id[i]) { + cpu_set(i, cpu_sibling_map[cpu]); + cpu_set(cpu, cpu_sibling_map[i]); + } + } + } else { + cpu_set(cpu, cpu_sibling_map[cpu]); + } + + if (current_cpu_data.x86_num_cores > 1) { + for_each_cpu(i) { + if (phys_proc_id[cpu] == phys_proc_id[i]) { + cpu_set(i, cpu_core_map[cpu]); + cpu_set(cpu, cpu_core_map[i]); + } + } + } else { + cpu_core_map[cpu] = cpu_sibling_map[cpu]; + } +} + /* * Setup code on secondary processor (after comming out of the trampoline) */ @@ -448,9 +502,28 @@ void __cpuinit start_secondary(void) enable_APIC_timer(); /* + * The sibling maps must be set before turing the online map on for + * this cpu + */ + set_cpu_sibling_map(smp_processor_id()); + + /* + * We need to hold call_lock, so there is no inconsistency + * between the time smp_call_function() determines number of + * IPI receipients, and the time when the determination is made + * for which cpus receive the IPI in genapic_flat.c. Holding this + * lock helps us to not include this cpu in a currently in progress + * smp_call_function(). + */ + lock_ipi_call_lock(); + + /* * Allow the master to continue. */ cpu_set(smp_processor_id(), cpu_online_map); + per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; + unlock_ipi_call_lock(); + mb(); /* Wait for TSC sync to not schedule things before. @@ -628,33 +701,77 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta return (send_status | accept_status); } +struct create_idle { + struct task_struct *idle; + struct completion done; + int cpu; +}; + +void do_fork_idle(void *_c_idle) +{ + struct create_idle *c_idle = _c_idle; + + c_idle->idle = fork_idle(c_idle->cpu); + complete(&c_idle->done); +} + /* * Boot one CPU. */ static int __cpuinit do_boot_cpu(int cpu, int apicid) { - struct task_struct *idle; unsigned long boot_error; int timeout; unsigned long start_rip; + struct create_idle c_idle = { + .cpu = cpu, + .done = COMPLETION_INITIALIZER(c_idle.done), + }; + DECLARE_WORK(work, do_fork_idle, &c_idle); + + c_idle.idle = get_idle_for_cpu(cpu); + + if (c_idle.idle) { + c_idle.idle->thread.rsp = (unsigned long) (((struct pt_regs *) + (THREAD_SIZE + (unsigned long) c_idle.idle->thread_info)) - 1); + init_idle(c_idle.idle, cpu); + goto do_rest; + } + /* - * We can't use kernel_thread since we must avoid to - * reschedule the child. + * During cold boot process, keventd thread is not spun up yet. + * When we do cpu hot-add, we create idle threads on the fly, we should + * not acquire any attributes from the calling context. Hence the clean + * way to create kernel_threads() is to do that from keventd(). + * We do the current_is_keventd() due to the fact that ACPI notifier + * was also queuing to keventd() and when the caller is already running + * in context of keventd(), we would end up with locking up the keventd + * thread. */ - idle = fork_idle(cpu); - if (IS_ERR(idle)) { + if (!keventd_up() || current_is_keventd()) + work.func(work.data); + else { + schedule_work(&work); + wait_for_completion(&c_idle.done); + } + + if (IS_ERR(c_idle.idle)) { printk("failed fork for CPU %d\n", cpu); - return PTR_ERR(idle); + return PTR_ERR(c_idle.idle); } - cpu_pda[cpu].pcurrent = idle; + set_idle_for_cpu(cpu, c_idle.idle); + +do_rest: + + cpu_pda[cpu].pcurrent = c_idle.idle; start_rip = setup_trampoline(); - init_rsp = idle->thread.rsp; + init_rsp = c_idle.idle->thread.rsp; per_cpu(init_tss,cpu).rsp0 = init_rsp; initial_code = start_secondary; - clear_ti_thread_flag(idle->thread_info, TIF_FORK); + clear_ti_thread_flag(c_idle.idle->thread_info, TIF_FORK); printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid, start_rip, init_rsp); @@ -746,51 +863,6 @@ cycles_t cacheflush_time; unsigned long cache_decay_ticks; /* - * Construct cpu_sibling_map[], so that we can tell the sibling CPU - * on SMT systems efficiently. - */ -static __cpuinit void detect_siblings(void) -{ - int cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - cpus_clear(cpu_sibling_map[cpu]); - cpus_clear(cpu_core_map[cpu]); - } - - for_each_online_cpu (cpu) { - struct cpuinfo_x86 *c = cpu_data + cpu; - int siblings = 0; - int i; - if (smp_num_siblings > 1) { - for_each_online_cpu (i) { - if (cpu_core_id[cpu] == cpu_core_id[i]) { - siblings++; - cpu_set(i, cpu_sibling_map[cpu]); - } - } - } else { - siblings++; - cpu_set(cpu, cpu_sibling_map[cpu]); - } - - if (siblings != smp_num_siblings) { - printk(KERN_WARNING - "WARNING: %d siblings found for CPU%d, should be %d\n", - siblings, cpu, smp_num_siblings); - smp_num_siblings = siblings; - } - if (c->x86_num_cores > 1) { - for_each_online_cpu(i) { - if (phys_proc_id[cpu] == phys_proc_id[i]) - cpu_set(i, cpu_core_map[cpu]); - } - } else - cpu_core_map[cpu] = cpu_sibling_map[cpu]; - } -} - -/* * Cleanup possible dangling ends... */ static __cpuinit void smp_cleanup_boot(void) @@ -823,7 +895,7 @@ static __cpuinit void smp_cleanup_boot(void) * * RED-PEN audit/test this more. I bet there is more state messed up here. */ -static __cpuinit void disable_smp(void) +static __init void disable_smp(void) { cpu_present_map = cpumask_of_cpu(0); cpu_possible_map = cpumask_of_cpu(0); @@ -838,7 +910,7 @@ static __cpuinit void disable_smp(void) /* * Handle user cpus=... parameter. */ -static __cpuinit void enforce_max_cpus(unsigned max_cpus) +static __init void enforce_max_cpus(unsigned max_cpus) { int i, k; k = 0; @@ -855,7 +927,7 @@ static __cpuinit void enforce_max_cpus(unsigned max_cpus) /* * Various sanity checks. */ -static int __cpuinit smp_sanity_check(unsigned max_cpus) +static int __init smp_sanity_check(unsigned max_cpus) { if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) { printk("weird, boot CPU (#%d) not listed by the BIOS.\n", @@ -913,7 +985,7 @@ static int __cpuinit smp_sanity_check(unsigned max_cpus) * Prepare for SMP bootup. The MP table or ACPI has been read * earlier. Just do some sanity checking here and enable APIC mode. */ -void __cpuinit smp_prepare_cpus(unsigned int max_cpus) +void __init smp_prepare_cpus(unsigned int max_cpus) { int i; @@ -930,10 +1002,9 @@ void __cpuinit smp_prepare_cpus(unsigned int max_cpus) int apicid = cpu_present_to_apicid(i); if (physid_isset(apicid, phys_cpu_present_map)) { cpu_set(i, cpu_present_map); - /* possible map would be different if we supported real - CPU hotplug. */ cpu_set(i, cpu_possible_map); } + fixup_cpu_possible_map(i); } if (smp_sanity_check(max_cpus) < 0) { @@ -978,13 +1049,13 @@ void __init smp_prepare_boot_cpu(void) int me = smp_processor_id(); cpu_set(me, cpu_online_map); cpu_set(me, cpu_callout_map); + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); + per_cpu(cpu_state, me) = CPU_ONLINE; } /* * Entry point to boot a CPU. - * - * This is all __cpuinit, not __devinit for now because we don't support - * CPU hotplug (yet). */ int __cpuinit __cpu_up(unsigned int cpu) { @@ -1001,6 +1072,15 @@ int __cpuinit __cpu_up(unsigned int cpu) return -EINVAL; } + /* + * Already booted CPU? + */ + if (cpu_isset(cpu, cpu_callin_map)) { + Dprintk("do_boot_cpu %d Already started\n", cpu); + return -ENOSYS; + } + + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; /* Boot it! */ err = do_boot_cpu(cpu, apicid); if (err < 0) { @@ -1013,23 +1093,118 @@ int __cpuinit __cpu_up(unsigned int cpu) while (!cpu_isset(cpu, cpu_online_map)) cpu_relax(); - return 0; + err = 0; + + return err; } /* * Finish the SMP boot. */ -void __cpuinit smp_cpus_done(unsigned int max_cpus) +void __init smp_cpus_done(unsigned int max_cpus) { +#ifndef CONFIG_HOTPLUG_CPU zap_low_mappings(); +#endif smp_cleanup_boot(); #ifdef CONFIG_X86_IO_APIC setup_ioapic_dest(); #endif - detect_siblings(); time_init_gtod(); check_nmi_watchdog(); } + +#ifdef CONFIG_HOTPLUG_CPU + +static void remove_siblinginfo(int cpu) +{ + int sibling; + + for_each_cpu_mask(sibling, cpu_sibling_map[cpu]) + cpu_clear(cpu, cpu_sibling_map[sibling]); + for_each_cpu_mask(sibling, cpu_core_map[cpu]) + cpu_clear(cpu, cpu_core_map[sibling]); + cpus_clear(cpu_sibling_map[cpu]); + cpus_clear(cpu_core_map[cpu]); + phys_proc_id[cpu] = BAD_APICID; + cpu_core_id[cpu] = BAD_APICID; +} + +void remove_cpu_from_maps(void) +{ + int cpu = smp_processor_id(); + + cpu_clear(cpu, cpu_callout_map); + cpu_clear(cpu, cpu_callin_map); + clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */ +} + +int __cpu_disable(void) +{ + int cpu = smp_processor_id(); + + /* + * Perhaps use cpufreq to drop frequency, but that could go + * into generic code. + * + * We won't take down the boot processor on i386 due to some + * interrupts only being able to be serviced by the BSP. + * Especially so if we're not using an IOAPIC -zwane + */ + if (cpu == 0) + return -EBUSY; + + disable_APIC_timer(); + + /* + * HACK: + * Allow any queued timer interrupts to get serviced + * This is only a temporary solution until we cleanup + * fixup_irqs as we do for IA64. + */ + local_irq_enable(); + mdelay(1); + + local_irq_disable(); + remove_siblinginfo(cpu); + + /* It's now safe to remove this processor from the online map */ + cpu_clear(cpu, cpu_online_map); + remove_cpu_from_maps(); + fixup_irqs(cpu_online_map); + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + /* We don't do anything here: idle task is faking death itself. */ + unsigned int i; + + for (i = 0; i < 10; i++) { + /* They ack this in play_dead by setting CPU_DEAD */ + if (per_cpu(cpu_state, cpu) == CPU_DEAD) { + printk ("CPU %d is now offline\n", cpu); + return; + } + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); + } + printk(KERN_ERR "CPU %u didn't die...\n", cpu); +} + +#else /* ... !CONFIG_HOTPLUG_CPU */ + +int __cpu_disable(void) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + /* We said "no" in __cpu_disable */ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index ebaa1e3..6c0f402e 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -44,7 +44,6 @@ void __save_processor_state(struct saved_context *ctxt) */ asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit)); asm volatile ("sidt %0" : "=m" (ctxt->idt_limit)); - asm volatile ("sldt %0" : "=m" (ctxt->ldt)); asm volatile ("str %0" : "=m" (ctxt->tr)); /* XMM0..XMM15 should be handled by kernel_fpu_begin(). */ @@ -69,6 +68,7 @@ void __save_processor_state(struct saved_context *ctxt) asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2)); asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3)); asm volatile ("movq %%cr4, %0" : "=r" (ctxt->cr4)); + asm volatile ("movq %%cr8, %0" : "=r" (ctxt->cr8)); } void save_processor_state(void) @@ -90,12 +90,20 @@ void __restore_processor_state(struct saved_context *ctxt) /* * control registers */ + asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8)); asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4)); asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3)); asm volatile ("movq %0, %%cr2" :: "r" (ctxt->cr2)); asm volatile ("movq %0, %%cr0" :: "r" (ctxt->cr0)); /* + * now restore the descriptor tables to their proper values + * ltr is done i fix_processor_context(). + */ + asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit)); + asm volatile ("lidt %0" :: "m" (ctxt->idt_limit)); + + /* * segment registers */ asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds)); @@ -108,14 +116,6 @@ void __restore_processor_state(struct saved_context *ctxt) wrmsrl(MSR_GS_BASE, ctxt->gs_base); wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); - /* - * now restore the descriptor tables to their proper values - * ltr is done i fix_processor_context(). - */ - asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit)); - asm volatile ("lidt %0" :: "m" (ctxt->idt_limit)); - asm volatile ("lldt %0" :: "m" (ctxt->ldt)); - fix_processor_context(); do_fpu_end(); diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 121646f..1027366 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -586,11 +586,17 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) asmlinkage void default_do_nmi(struct pt_regs *regs) { unsigned char reason = 0; + int cpu; + + cpu = smp_processor_id(); /* Only the BSP gets external NMIs from the system. */ - if (!smp_processor_id()) + if (!cpu) reason = get_nmi_reason(); + if (!cpu_online(cpu)) + return; + if (!(reason & 0xc0)) { if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) == NOTIFY_STOP) diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index 59ebd5b..73389f5 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -2,7 +2,10 @@ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>; */ +#define LOAD_OFFSET __START_KERNEL_map + #include <asm-generic/vmlinux.lds.h> +#include <asm/page.h> #include <linux/config.h> OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") @@ -11,28 +14,30 @@ ENTRY(phys_startup_64) jiffies_64 = jiffies; SECTIONS { - . = 0xffffffff80100000; + . = __START_KERNEL; phys_startup_64 = startup_64 - LOAD_OFFSET; _text = .; /* Text and read-only data */ - .text : { + .text : AT(ADDR(.text) - LOAD_OFFSET) { *(.text) SCHED_TEXT LOCK_TEXT *(.fixup) *(.gnu.warning) } = 0x9090 - .text.lock : { *(.text.lock) } /* out-of-line lock text */ + /* out-of-line lock text */ + .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) } _etext = .; /* End of text section */ . = ALIGN(16); /* Exception table */ __start___ex_table = .; - __ex_table : { *(__ex_table) } + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } __stop___ex_table = .; RODATA - .data : { /* Data */ + /* Data */ + .data : AT(ADDR(.data) - LOAD_OFFSET) { *(.data) CONSTRUCTORS } @@ -40,62 +45,95 @@ SECTIONS _edata = .; /* End of data section */ __bss_start = .; /* BSS */ - .bss : { + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { *(.bss.page_aligned) *(.bss) } __bss_end = .; + . = ALIGN(PAGE_SIZE); . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + *(.data.cacheline_aligned) + } + +#define VSYSCALL_ADDR (-10*1024*1024) +#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) +#define VSYSCALL_VIRT_ADDR ((ADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) + +#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR) +#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) + +#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR) +#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) -#define AFTER(x) BINALIGN(LOADADDR(x) + SIZEOF(x), 16) -#define BINALIGN(x,y) (((x) + (y) - 1) & ~((y) - 1)) -#define CACHE_ALIGN(x) BINALIGN(x, CONFIG_X86_L1_CACHE_BYTES) + . = VSYSCALL_ADDR; + .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) } + __vsyscall_0 = VSYSCALL_VIRT_ADDR; - .vsyscall_0 -10*1024*1024: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) } - __vsyscall_0 = LOADADDR(.vsyscall_0); . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .xtime_lock : AT CACHE_ALIGN(AFTER(.vsyscall_0)) { *(.xtime_lock) } - xtime_lock = LOADADDR(.xtime_lock); - .vxtime : AT AFTER(.xtime_lock) { *(.vxtime) } - vxtime = LOADADDR(.vxtime); - .wall_jiffies : AT AFTER(.vxtime) { *(.wall_jiffies) } - wall_jiffies = LOADADDR(.wall_jiffies); - .sys_tz : AT AFTER(.wall_jiffies) { *(.sys_tz) } - sys_tz = LOADADDR(.sys_tz); - .sysctl_vsyscall : AT AFTER(.sys_tz) { *(.sysctl_vsyscall) } - sysctl_vsyscall = LOADADDR(.sysctl_vsyscall); - .xtime : AT AFTER(.sysctl_vsyscall) { *(.xtime) } - xtime = LOADADDR(.xtime); + .xtime_lock : AT(VLOAD(.xtime_lock)) { *(.xtime_lock) } + xtime_lock = VVIRT(.xtime_lock); + + .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) } + vxtime = VVIRT(.vxtime); + + .wall_jiffies : AT(VLOAD(.wall_jiffies)) { *(.wall_jiffies) } + wall_jiffies = VVIRT(.wall_jiffies); + + .sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) } + sys_tz = VVIRT(.sys_tz); + + .sysctl_vsyscall : AT(VLOAD(.sysctl_vsyscall)) { *(.sysctl_vsyscall) } + sysctl_vsyscall = VVIRT(.sysctl_vsyscall); + + .xtime : AT(VLOAD(.xtime)) { *(.xtime) } + xtime = VVIRT(.xtime); + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); - .jiffies : AT CACHE_ALIGN(AFTER(.xtime)) { *(.jiffies) } - jiffies = LOADADDR(.jiffies); - .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) } - . = LOADADDR(.vsyscall_0) + 4096; + .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) } + jiffies = VVIRT(.jiffies); + + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) { *(.vsyscall_1) } + .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) { *(.vsyscall_2) } + .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { *(.vsyscall_3) } + + . = VSYSCALL_VIRT_ADDR + 4096; + +#undef VSYSCALL_ADDR +#undef VSYSCALL_PHYS_ADDR +#undef VSYSCALL_VIRT_ADDR +#undef VLOAD_OFFSET +#undef VLOAD +#undef VVIRT_OFFSET +#undef VVIRT . = ALIGN(8192); /* init_task */ - .data.init_task : { *(.data.init_task) } + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + } . = ALIGN(4096); - .data.page_aligned : { *(.data.page_aligned) } + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) + } . = ALIGN(4096); /* Init code and data */ __init_begin = .; - .init.text : { + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; *(.init.text) _einittext = .; } __initdata_begin = .; - .init.data : { *(.init.data) } + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } __initdata_end = .; . = ALIGN(16); __setup_start = .; - .init.setup : { *(.init.setup) } + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) } __setup_end = .; __initcall_start = .; - .initcall.init : { + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { *(.initcall1.init) *(.initcall2.init) *(.initcall3.init) @@ -106,32 +144,38 @@ SECTIONS } __initcall_end = .; __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + *(.con_initcall.init) + } __con_initcall_end = .; SECURITY_INIT . = ALIGN(8); __alt_instructions = .; - .altinstructions : { *(.altinstructions) } + .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) { + *(.altinstructions) + } __alt_instructions_end = .; - .altinstr_replacement : { *(.altinstr_replacement) } + .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { + *(.altinstr_replacement) + } /* .exit.text is discard at runtime, not link time, to deal with references from .altinstructions and .eh_frame */ - .exit.text : { *(.exit.text) } - .exit.data : { *(.exit.data) } + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } . = ALIGN(4096); __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) } __initramfs_end = .; . = ALIGN(32); __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } + .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } __per_cpu_end = .; . = ALIGN(4096); __init_end = .; . = ALIGN(4096); __nosave_begin = .; - .data_nosave : { *(.data.nosave) } + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } . = ALIGN(4096); __nosave_end = .; diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 84cde79..ac61c18 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -251,7 +251,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT); } -__init void numa_add_cpu(int cpu) +__cpuinit void numa_add_cpu(int cpu) { /* BP is initialized elsewhere */ if (cpu) diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c index 9e2b53f..4fbddf9 100644 --- a/arch/xtensa/platform-iss/console.c +++ b/arch/xtensa/platform-iss/console.c @@ -198,9 +198,6 @@ static int rs_read_proc(char *page, char **start, off_t off, int count, } -int register_serial(struct serial_struct*); -void unregister_serial(int); - static struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 670fdb5..86c5252 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -55,7 +55,7 @@ if ACPI_INTERPRETER config ACPI_SLEEP bool "Sleep States (EXPERIMENTAL)" - depends on X86 + depends on X86 && (!SMP || SUSPEND_SMP) depends on EXPERIMENTAL && PM default y ---help--- diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 8093f2e..8dbf802 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -435,6 +435,7 @@ acpi_pci_irq_enable ( /* Interrupt Line values above 0xF are forbidden */ if (dev->irq >= 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); + acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return_VALUE(0); } else { diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 6ef3069..b79badd 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -16,6 +16,11 @@ struct sysdev_class cpu_sysdev_class = { EXPORT_SYMBOL(cpu_sysdev_class); #ifdef CONFIG_HOTPLUG_CPU +int __attribute__((weak)) smp_prepare_cpu (int cpu) +{ + return 0; +} + static ssize_t show_online(struct sys_device *dev, char *buf) { struct cpu *cpu = container_of(dev, struct cpu, sysdev); @@ -36,7 +41,11 @@ static ssize_t store_online(struct sys_device *dev, const char *buf, kobject_hotplug(&dev->kobj, KOBJ_OFFLINE); break; case '1': - ret = cpu_up(cpu->sysdev.id); + ret = smp_prepare_cpu(cpu->sysdev.id); + if (!ret) + ret = cpu_up(cpu->sysdev.id); + if (!ret) + kobject_hotplug(&dev->kobj, KOBJ_ONLINE); break; default: ret = -EINVAL; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index fd94ea2..60e6409 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -37,6 +37,7 @@ static void blk_unplug_work(void *data); static void blk_unplug_timeout(unsigned long data); +static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io); /* * For the allocated request tables @@ -1137,7 +1138,7 @@ new_hw_segment: } -int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, +static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, struct bio *nxt) { if (!(q->queue_flags & (1 << QUEUE_FLAG_CLUSTER))) @@ -1158,9 +1159,7 @@ int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, return 0; } -EXPORT_SYMBOL(blk_phys_contig_segment); - -int blk_hw_contig_segment(request_queue_t *q, struct bio *bio, +static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio, struct bio *nxt) { if (unlikely(!bio_flagged(bio, BIO_SEG_VALID))) @@ -1176,8 +1175,6 @@ int blk_hw_contig_segment(request_queue_t *q, struct bio *bio, return 1; } -EXPORT_SYMBOL(blk_hw_contig_segment); - /* * map a request to scatterlist, return number of sg entries setup. Caller * must make sure sg can hold rq->nr_phys_segments entries @@ -1347,8 +1344,8 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req, static int ll_merge_requests_fn(request_queue_t *q, struct request *req, struct request *next) { - int total_phys_segments = req->nr_phys_segments +next->nr_phys_segments; - int total_hw_segments = req->nr_hw_segments + next->nr_hw_segments; + int total_phys_segments; + int total_hw_segments; /* * First check if the either of the requests are re-queued @@ -1358,7 +1355,7 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req, return 0; /* - * Will it become to large? + * Will it become too large? */ if ((req->nr_sectors + next->nr_sectors) > q->max_sectors) return 0; @@ -1825,7 +1822,7 @@ static inline int ioc_batching(request_queue_t *q, struct io_context *ioc) * is the behaviour we want though - once it gets a wakeup it should be given * a nice run. */ -void ioc_set_batching(request_queue_t *q, struct io_context *ioc) +static void ioc_set_batching(request_queue_t *q, struct io_context *ioc) { if (!ioc || ioc_batching(q, ioc)) return; @@ -2254,45 +2251,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) EXPORT_SYMBOL(blkdev_issue_flush); -/** - * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices - * @q: device queue - * @disk: gendisk - * @error_sector: error offset - * - * Description: - * Devices understanding the SCSI command set, can use this function as - * a helper for issuing a cache flush. Note: driver is required to store - * the error offset (in case of error flushing) in ->sector of struct - * request. - */ -int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, - sector_t *error_sector) -{ - struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT); - int ret; - - rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; - rq->sector = 0; - memset(rq->cmd, 0, sizeof(rq->cmd)); - rq->cmd[0] = 0x35; - rq->cmd_len = 12; - rq->data = NULL; - rq->data_len = 0; - rq->timeout = 60 * HZ; - - ret = blk_execute_rq(q, disk, rq); - - if (ret && error_sector) - *error_sector = rq->sector; - - blk_put_request(rq); - return ret; -} - -EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn); - -void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) +static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); @@ -2551,16 +2510,6 @@ void blk_attempt_remerge(request_queue_t *q, struct request *rq) EXPORT_SYMBOL(blk_attempt_remerge); -/* - * Non-locking blk_attempt_remerge variant. - */ -void __blk_attempt_remerge(request_queue_t *q, struct request *rq) -{ - attempt_back_merge(q, rq); -} - -EXPORT_SYMBOL(__blk_attempt_remerge); - static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; @@ -2971,7 +2920,7 @@ void submit_bio(int rw, struct bio *bio) EXPORT_SYMBOL(submit_bio); -void blk_recalc_rq_segments(struct request *rq) +static void blk_recalc_rq_segments(struct request *rq) { struct bio *bio, *prevbio = NULL; int nr_phys_segs, nr_hw_segs; @@ -3013,7 +2962,7 @@ void blk_recalc_rq_segments(struct request *rq) rq->nr_hw_segments = nr_hw_segs; } -void blk_recalc_rq_sectors(struct request *rq, int nsect) +static void blk_recalc_rq_sectors(struct request *rq, int nsect) { if (blk_fs_request(rq)) { rq->hard_sector += nsect; @@ -3601,7 +3550,7 @@ static struct sysfs_ops queue_sysfs_ops = { .store = queue_attr_store, }; -struct kobj_type queue_ktype = { +static struct kobj_type queue_ktype = { .sysfs_ops = &queue_sysfs_ops, .default_attrs = default_attrs, }; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7f3d78d..7b83834 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1251,8 +1251,7 @@ static int kcdrwd(void *foobar) VPRINTK("kcdrwd: wake up\n"); /* make swsusp happy with our thread */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { if (!pkt->sleep_time) diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index da80b14..01f0351 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -307,7 +307,7 @@ static DEFINE_SPINLOCK(cm206_lock); /* First, we define some polling functions. These are actually only being used in the initialization. */ -void send_command_polled(int command) +static void send_command_polled(int command) { int loop = POLLOOP; while (!(inw(r_line_status) & ls_transmitter_buffer_empty) @@ -318,7 +318,7 @@ void send_command_polled(int command) outw(command, r_uart_transmit); } -uch receive_echo_polled(void) +static uch receive_echo_polled(void) { int loop = POLLOOP; while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) { @@ -328,13 +328,13 @@ uch receive_echo_polled(void) return ((uch) inw(r_uart_receive)); } -uch send_receive_polled(int command) +static uch send_receive_polled(int command) { send_command_polled(command); return receive_echo_polled(); } -inline void clear_ur(void) +static inline void clear_ur(void) { if (cd->ur_r != cd->ur_w) { debug(("Deleting bytes from fifo:")); @@ -439,7 +439,7 @@ static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs) } /* we have put the address of the wait queue in who */ -void cm206_timeout(unsigned long who) +static void cm206_timeout(unsigned long who) { cd->timed_out = 1; debug(("Timing out\n")); @@ -448,7 +448,7 @@ void cm206_timeout(unsigned long who) /* This function returns 1 if a timeout occurred, 0 if an interrupt happened */ -int sleep_or_timeout(wait_queue_head_t * wait, int timeout) +static int sleep_or_timeout(wait_queue_head_t * wait, int timeout) { cd->timed_out = 0; init_timer(&cd->timer); @@ -465,13 +465,7 @@ int sleep_or_timeout(wait_queue_head_t * wait, int timeout) return 0; } -void cm206_delay(int nr_jiffies) -{ - DECLARE_WAIT_QUEUE_HEAD(wait); - sleep_or_timeout(&wait, nr_jiffies); -} - -void send_command(int command) +static void send_command(int command) { debug(("Sending 0x%x\n", command)); if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) { @@ -490,7 +484,7 @@ void send_command(int command) outw(command, r_uart_transmit); } -uch receive_byte(int timeout) +static uch receive_byte(int timeout) { uch ret; cli(); @@ -521,23 +515,23 @@ uch receive_byte(int timeout) return ret; } -inline uch receive_echo(void) +static inline uch receive_echo(void) { return receive_byte(UART_TIMEOUT); } -inline uch send_receive(int command) +static inline uch send_receive(int command) { send_command(command); return receive_echo(); } -inline uch wait_dsb(void) +static inline uch wait_dsb(void) { return receive_byte(DSB_TIMEOUT); } -int type_0_command(int command, int expect_dsb) +static int type_0_command(int command, int expect_dsb) { int e; clear_ur(); @@ -552,7 +546,7 @@ int type_0_command(int command, int expect_dsb) return 0; } -int type_1_command(int command, int bytes, uch * status) +static int type_1_command(int command, int bytes, uch * status) { /* returns info */ int i; if (type_0_command(command, 0)) @@ -564,7 +558,7 @@ int type_1_command(int command, int bytes, uch * status) /* This function resets the adapter card. We'd better not do this too * often, because it tends to generate `lost interrupts.' */ -void reset_cm260(void) +static void reset_cm260(void) { outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control); udelay(10); /* 3.3 mu sec minimum */ @@ -572,7 +566,7 @@ void reset_cm260(void) } /* fsm: frame-sec-min from linear address; one of many */ -void fsm(int lba, uch * fsm) +static void fsm(int lba, uch * fsm) { fsm[0] = lba % 75; lba /= 75; @@ -581,17 +575,17 @@ void fsm(int lba, uch * fsm) fsm[2] = lba / 60; } -inline int fsm2lba(uch * fsm) +static inline int fsm2lba(uch * fsm) { return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]); } -inline int f_s_m2lba(uch f, uch s, uch m) +static inline int f_s_m2lba(uch f, uch s, uch m) { return f + 75 * (s - 2 + 60 * m); } -int start_read(int start) +static int start_read(int start) { uch read_sector[4] = { c_read_data, }; int i, e; @@ -613,7 +607,7 @@ int start_read(int start) return 0; } -int stop_read(void) +static int stop_read(void) { int e; type_0_command(c_stop, 0); @@ -630,7 +624,7 @@ int stop_read(void) routine takes care of this. Set a flag `background' in the cd struct to indicate the process. */ -int read_background(int start, int reading) +static int read_background(int start, int reading) { if (cd->background) return -1; /* can't do twice */ @@ -658,7 +652,7 @@ void transport_data(int port, ush * dest, int count) #define MAX_TRIES 100 -int read_sector(int start) +static int read_sector(int start) { int tries = 0; if (cd->background) { @@ -753,7 +747,7 @@ static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0); /* This command clears the dsb_possible_media_change flag, so we must * retain it. */ -void get_drive_status(void) +static void get_drive_status(void) { uch status[2]; type_1_command(c_drive_status, 2, status); /* this might be done faster */ @@ -764,7 +758,7 @@ void get_drive_status(void) dsb_drive_not_ready | dsb_tray_not_closed)); } -void get_disc_status(void) +static void get_disc_status(void) { if (type_1_command(c_disc_status, 7, cd->disc_status)) { debug(("get_disc_status: error\n")); @@ -801,7 +795,7 @@ static void cm206_release(struct cdrom_device_info *cdi) /* Empty buffer empties $sectors$ sectors of the adapter card buffer, * and then reads a sector in kernel memory. */ -void empty_buffer(int sectors) +static void empty_buffer(int sectors) { while (sectors >= 0) { transport_data(r_fifo_output_buffer, @@ -819,7 +813,7 @@ void empty_buffer(int sectors) /* try_adapter. This function determines if the requested sector is in adapter memory, or will appear there soon. Returns 0 upon success */ -int try_adapter(int sector) +static int try_adapter(int sector) { if (cd->adapter_first <= sector && sector < cd->adapter_last) { /* sector is in adapter memory */ @@ -910,7 +904,7 @@ static void do_cm206_request(request_queue_t * q) */ /* seek seeks to address lba. It does wait to arrive there. */ -void seek(int lba) +static void seek(int lba) { int i; uch seek_command[4] = { c_seek, }; @@ -926,7 +920,7 @@ uch bcdbin(unsigned char bcd) return (bcd >> 4) * 10 + (bcd & 0xf); } -inline uch normalize_track(uch track) +static inline uch normalize_track(uch track) { if (track < 1) return 1; @@ -939,7 +933,7 @@ inline uch normalize_track(uch track) * tracks seen in the process. Input $track$ must be between 1 and * #-of-tracks+1. Note that the start of the disc must be in toc[1].fsm. */ -int get_toc_lba(uch track) +static int get_toc_lba(uch track) { int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm); int i, lba, l, old_lba = 0; @@ -991,7 +985,7 @@ int get_toc_lba(uch track) return lba; } -void update_toc_entry(uch track) +static void update_toc_entry(uch track) { track = normalize_track(track); if (!cd->toc[track].track) @@ -999,7 +993,7 @@ void update_toc_entry(uch track) } /* return 0 upon success */ -int read_toc_header(struct cdrom_tochdr *hp) +static int read_toc_header(struct cdrom_tochdr *hp) { if (!FIRST_TRACK) get_disc_status(); @@ -1016,7 +1010,7 @@ int read_toc_header(struct cdrom_tochdr *hp) return -1; } -void play_from_to_msf(struct cdrom_msf *msfp) +static void play_from_to_msf(struct cdrom_msf *msfp) { uch play_command[] = { c_play, msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0, @@ -1032,7 +1026,7 @@ void play_from_to_msf(struct cdrom_msf *msfp) cd->dsb = wait_dsb(); } -void play_from_to_track(int from, int to) +static void play_from_to_track(int from, int to) { uch play_command[8] = { c_play, }; int i; @@ -1059,7 +1053,7 @@ void play_from_to_track(int from, int to) cd->dsb = wait_dsb(); } -int get_current_q(struct cdrom_subchnl *qp) +static int get_current_q(struct cdrom_subchnl *qp) { int i; uch *q = cd->q; @@ -1093,14 +1087,14 @@ int get_current_q(struct cdrom_subchnl *qp) return 0; } -void invalidate_toc(void) +static void invalidate_toc(void) { memset(cd->toc, 0, sizeof(cd->toc)); memset(cd->disc_status, 0, sizeof(cd->disc_status)); } /* cdrom.c guarantees that cdte_format == CDROM_MSF */ -void get_toc_entry(struct cdrom_tocentry *ep) +static void get_toc_entry(struct cdrom_tocentry *ep) { uch track = normalize_track(ep->cdte_track); update_toc_entry(track); @@ -1117,8 +1111,8 @@ void get_toc_entry(struct cdrom_tocentry *ep) * upon success. Memory checking has been done by cdrom_ioctl(), the * calling function, as well as LBA/MSF sanitization. */ -int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, - void *arg) +static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + void *arg) { switch (cmd) { case CDROMREADTOCHDR: @@ -1189,7 +1183,7 @@ static int cm206_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, } } -int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr) +static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr) { if (cd != NULL) { int r; @@ -1204,16 +1198,9 @@ int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr) /* The new generic cdrom support. Routines should be concise, most of the logic should be in cdrom.c */ -/* returns number of times device is in use */ -int cm206_open_files(struct cdrom_device_info *cdi) -{ - if (cd) - return cd->openfiles; - return -1; -} /* controls tray movement */ -int cm206_tray_move(struct cdrom_device_info *cdi, int position) +static int cm206_tray_move(struct cdrom_device_info *cdi, int position) { if (position) { /* 1: eject */ type_0_command(c_open_tray, 1); @@ -1224,7 +1211,7 @@ int cm206_tray_move(struct cdrom_device_info *cdi, int position) } /* gives current state of the drive */ -int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr) +static int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr) { get_drive_status(); if (cd->dsb & dsb_tray_not_closed) @@ -1237,7 +1224,7 @@ int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr) } /* locks or unlocks door lock==1: lock; return 0 upon success */ -int cm206_lock_door(struct cdrom_device_info *cdi, int lock) +static int cm206_lock_door(struct cdrom_device_info *cdi, int lock) { uch command = (lock) ? c_lock_tray : c_unlock_tray; type_0_command(command, 1); /* wait and get dsb */ @@ -1248,8 +1235,8 @@ int cm206_lock_door(struct cdrom_device_info *cdi, int lock) /* Although a session start should be in LBA format, we return it in MSF format because it is slightly easier, and the new generic ioctl will take care of the necessary conversion. */ -int cm206_get_last_session(struct cdrom_device_info *cdi, - struct cdrom_multisession *mssp) +static int cm206_get_last_session(struct cdrom_device_info *cdi, + struct cdrom_multisession *mssp) { if (!FIRST_TRACK) get_disc_status(); @@ -1268,7 +1255,7 @@ int cm206_get_last_session(struct cdrom_device_info *cdi, return 0; } -int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) +static int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) { uch upc[10]; char *ret = mcn->medium_catalog_number; @@ -1287,7 +1274,7 @@ int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) return 0; } -int cm206_reset(struct cdrom_device_info *cdi) +static int cm206_reset(struct cdrom_device_info *cdi) { stop_read(); reset_cm260(); @@ -1300,7 +1287,7 @@ int cm206_reset(struct cdrom_device_info *cdi) return 0; } -int cm206_select_speed(struct cdrom_device_info *cdi, int speed) +static int cm206_select_speed(struct cdrom_device_info *cdi, int speed) { int r; switch (speed) { @@ -1392,7 +1379,7 @@ static struct gendisk *cm206_gendisk; request_region, 15 bits of one port and 6 of another make things likely enough to accept the region on the first hit... */ -int __init probe_base_port(int base) +static int __init probe_base_port(int base) { int b = 0x300, e = 0x370; /* this is the range of start addresses */ volatile int fool, i; @@ -1416,7 +1403,7 @@ int __init probe_base_port(int base) #if !defined(MODULE) || defined(AUTO_PROBE_MODULE) /* Probe for irq# nr. If nr==0, probe for all possible irq's. */ -int __init probe_irq(int nr) +static int __init probe_irq(int nr) { int irqs, irq; outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ @@ -1558,7 +1545,7 @@ static void __init parse_options(void) } } -int __cm206_init(void) +static int __cm206_init(void) { parse_options(); #if !defined(AUTO_PROBE_MODULE) @@ -1567,7 +1554,7 @@ int __cm206_init(void) return cm206_init(); } -void __exit cm206_exit(void) +static void __exit cm206_exit(void) { del_gendisk(cm206_gendisk); put_disk(cm206_gendisk); diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index f4be7bf..9f22e8f 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -1605,8 +1605,7 @@ out7: put_disk(cdu_disk); out6: for (i = 0; i < sony_buffer_sectors; i++) - if (sony_buffer[i]) - kfree(sony_buffer[i]); + kfree(sony_buffer[i]); out5: kfree(sony_buffer); out4: diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7ccf871..43d0cb1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -940,8 +940,8 @@ config RAW_DRIVER Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. See the raw(8) manpage for more details. - The raw driver is deprecated and may be removed from 2.7 - kernels. Applications should simply open the device (eg /dev/hda1) + The raw driver is deprecated and will be removed soon. + Applications should simply open the device (eg /dev/hda1) with the O_DIRECT flag. config HPET diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 777bc49..2a36561 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1973,10 +1973,6 @@ static _INLINE_ void show_serial_version(void) } -int register_serial(struct serial_struct *req); -void unregister_serial(int line); - - static struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 6bf2e27..11f9ee5 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -599,7 +599,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_ #ifdef DEBUG if (loopcount++ > 2) { - printk("Looping in ac_read. loopcount %d\n", loopcount); + printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount); } #endif } diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index d9a0299..c2b12ea 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig @@ -6,7 +6,7 @@ # config DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" - depends on AGP || AGP=n + depends on (AGP || AGP=n) && PCI help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index 23ab263..7444dec 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -19,6 +19,11 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_ds.o sis_mm.o +ifeq ($(CONFIG_COMPAT),y) +drm-objs += drm_ioc32.o +radeon-objs += radeon_ioc32.o +endif + obj-$(CONFIG_DRM) += drm.o obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 21f4c54..b04ddf1 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -316,6 +316,9 @@ do { \ typedef int drm_ioctl_t( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); +typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, + unsigned long arg); + typedef struct drm_ioctl_desc { drm_ioctl_t *func; int auth_needed; @@ -775,6 +778,8 @@ extern int drm_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern long drm_compat_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); extern int drm_takedown(drm_device_t * dev); /* Device support (drm_fops.h) */ diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 4113bcb..3407380 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -60,6 +60,15 @@ int drm_order( unsigned long size ) } EXPORT_SYMBOL(drm_order); +#ifdef CONFIG_COMPAT +/* + * Used to allocate 32-bit handles for _DRM_SHM regions + * The 0x10000000 value is chosen to be out of the way of + * FB/register and GART physical addresses. + */ +static unsigned int map32_handle = 0x10000000; +#endif + /** * Ioctl to specify a range of memory that is available for mapping by a non-root process. * @@ -187,16 +196,18 @@ int drm_addmap( struct inode *inode, struct file *filp, down(&dev->struct_sem); list_add(&list->head, &dev->maplist->head); +#ifdef CONFIG_COMPAT + /* Assign a 32-bit handle for _DRM_SHM mappings */ + /* We do it here so that dev->struct_sem protects the increment */ + if (map->type == _DRM_SHM) + map->offset = map32_handle += PAGE_SIZE; +#endif up(&dev->struct_sem); if ( copy_to_user( argp, map, sizeof(*map) ) ) return -EFAULT; - if ( map->type != _DRM_SHM ) { - if ( copy_to_user( &argp->handle, - &map->offset, - sizeof(map->offset) ) ) - return -EFAULT; - } + if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset))) + return -EFAULT; return 0; } @@ -240,7 +251,7 @@ int drm_rmmap(struct inode *inode, struct file *filp, r_list = list_entry(list, drm_map_list_t, head); if(r_list->map && - r_list->map->handle == request.handle && + r_list->map->offset == (unsigned long) request.handle && r_list->map->flags & _DRM_REMOVABLE) break; } diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index f15c86c..fdf661f 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -225,7 +225,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp, map = dev->context_sareas[request.ctx_id]; up(&dev->struct_sem); - request.handle = map->handle; + request.handle = (void *) map->offset; if (copy_to_user(argp, &request, sizeof(request))) return -EFAULT; return 0; @@ -261,8 +261,8 @@ int drm_setsareactx(struct inode *inode, struct file *filp, down(&dev->struct_sem); list_for_each(list, &dev->maplist->head) { r_list = list_entry(list, drm_map_list_t, head); - if(r_list->map && - r_list->map->handle == request.handle) + if (r_list->map + && r_list->map->offset == (unsigned long) request.handle) goto found; } bad: diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c new file mode 100644 index 0000000..8087a96 --- /dev/null +++ b/drivers/char/drm/drm_ioc32.c @@ -0,0 +1,1069 @@ +/** + * \file drm_ioc32.c + * + * 32-bit ioctl compatibility routines for the DRM. + * + * \author Paul Mackerras <paulus@samba.org> + * + * Copyright (C) Paul Mackerras 2005. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <linux/compat.h> +#include <linux/ioctl32.h> + +#include "drmP.h" +#include "drm_core.h" + +#define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) +#define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) +#define DRM_IOCTL_GET_MAP32 DRM_IOWR(0x04, drm_map32_t) +#define DRM_IOCTL_GET_CLIENT32 DRM_IOWR(0x05, drm_client32_t) +#define DRM_IOCTL_GET_STATS32 DRM_IOR( 0x06, drm_stats32_t) + +#define DRM_IOCTL_SET_UNIQUE32 DRM_IOW( 0x10, drm_unique32_t) +#define DRM_IOCTL_ADD_MAP32 DRM_IOWR(0x15, drm_map32_t) +#define DRM_IOCTL_ADD_BUFS32 DRM_IOWR(0x16, drm_buf_desc32_t) +#define DRM_IOCTL_MARK_BUFS32 DRM_IOW( 0x17, drm_buf_desc32_t) +#define DRM_IOCTL_INFO_BUFS32 DRM_IOWR(0x18, drm_buf_info32_t) +#define DRM_IOCTL_MAP_BUFS32 DRM_IOWR(0x19, drm_buf_map32_t) +#define DRM_IOCTL_FREE_BUFS32 DRM_IOW( 0x1a, drm_buf_free32_t) + +#define DRM_IOCTL_RM_MAP32 DRM_IOW( 0x1b, drm_map32_t) + +#define DRM_IOCTL_SET_SAREA_CTX32 DRM_IOW( 0x1c, drm_ctx_priv_map32_t) +#define DRM_IOCTL_GET_SAREA_CTX32 DRM_IOWR(0x1d, drm_ctx_priv_map32_t) + +#define DRM_IOCTL_RES_CTX32 DRM_IOWR(0x26, drm_ctx_res32_t) +#define DRM_IOCTL_DMA32 DRM_IOWR(0x29, drm_dma32_t) + +#define DRM_IOCTL_AGP_ENABLE32 DRM_IOW( 0x32, drm_agp_mode32_t) +#define DRM_IOCTL_AGP_INFO32 DRM_IOR( 0x33, drm_agp_info32_t) +#define DRM_IOCTL_AGP_ALLOC32 DRM_IOWR(0x34, drm_agp_buffer32_t) +#define DRM_IOCTL_AGP_FREE32 DRM_IOW( 0x35, drm_agp_buffer32_t) +#define DRM_IOCTL_AGP_BIND32 DRM_IOW( 0x36, drm_agp_binding32_t) +#define DRM_IOCTL_AGP_UNBIND32 DRM_IOW( 0x37, drm_agp_binding32_t) + +#define DRM_IOCTL_SG_ALLOC32 DRM_IOW( 0x38, drm_scatter_gather32_t) +#define DRM_IOCTL_SG_FREE32 DRM_IOW( 0x39, drm_scatter_gather32_t) + +#define DRM_IOCTL_WAIT_VBLANK32 DRM_IOWR(0x3a, drm_wait_vblank32_t) + +typedef struct drm_version_32 { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel;/**< Patch level */ + u32 name_len; /**< Length of name buffer */ + u32 name; /**< Name of driver */ + u32 date_len; /**< Length of date buffer */ + u32 date; /**< User-space buffer to hold date */ + u32 desc_len; /**< Length of desc buffer */ + u32 desc; /**< User-space buffer to hold desc */ +} drm_version32_t; + +static int compat_drm_version(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_version32_t v32; + drm_version_t __user *version; + int err; + + if (copy_from_user(&v32, (void __user *) arg, sizeof(v32))) + return -EFAULT; + + version = compat_alloc_user_space(sizeof(*version)); + if (!access_ok(VERIFY_WRITE, version, sizeof(*version))) + return -EFAULT; + if (__put_user(v32.name_len, &version->name_len) + || __put_user((void __user *)(unsigned long)v32.name, + &version->name) + || __put_user(v32.date_len, &version->date_len) + || __put_user((void __user *)(unsigned long)v32.date, + &version->date) + || __put_user(v32.desc_len, &version->desc_len) + || __put_user((void __user *)(unsigned long)v32.desc, + &version->desc)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_VERSION, (unsigned long) version); + if (err) + return err; + + if (__get_user(v32.version_major, &version->version_major) + || __get_user(v32.version_minor, &version->version_minor) + || __get_user(v32.version_patchlevel, &version->version_patchlevel) + || __get_user(v32.name_len, &version->name_len) + || __get_user(v32.date_len, &version->date_len) + || __get_user(v32.desc_len, &version->desc_len)) + return -EFAULT; + + if (copy_to_user((void __user *) arg, &v32, sizeof(v32))) + return -EFAULT; + return 0; +} + +typedef struct drm_unique32 { + u32 unique_len; /**< Length of unique */ + u32 unique; /**< Unique name for driver instantiation */ +} drm_unique32_t; + +static int compat_drm_getunique(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_unique32_t uq32; + drm_unique_t __user *u; + int err; + + if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32))) + return -EFAULT; + + u = compat_alloc_user_space(sizeof(*u)); + if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + return -EFAULT; + if (__put_user(uq32.unique_len, &u->unique_len) + || __put_user((void __user *)(unsigned long) uq32.unique, + &u->unique)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_GET_UNIQUE, (unsigned long) u); + if (err) + return err; + + if (__get_user(uq32.unique_len, &u->unique_len)) + return -EFAULT; + if (copy_to_user((void __user *) arg, &uq32, sizeof(uq32))) + return -EFAULT; + return 0; +} + +static int compat_drm_setunique(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_unique32_t uq32; + drm_unique_t __user *u; + + if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32))) + return -EFAULT; + + u = compat_alloc_user_space(sizeof(*u)); + if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + return -EFAULT; + if (__put_user(uq32.unique_len, &u->unique_len) + || __put_user((void __user *)(unsigned long) uq32.unique, + &u->unique)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_SET_UNIQUE, (unsigned long) u); +} + +typedef struct drm_map32 { + u32 offset; /**< Requested physical address (0 for SAREA)*/ + u32 size; /**< Requested physical size (bytes) */ + drm_map_type_t type; /**< Type of memory to map */ + drm_map_flags_t flags; /**< Flags */ + u32 handle; /**< User-space: "Handle" to pass to mmap() */ + int mtrr; /**< MTRR slot used */ +} drm_map32_t; + +static int compat_drm_getmap(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_map32_t __user *argp = (void __user *)arg; + drm_map32_t m32; + drm_map_t __user *map; + int idx, err; + void *handle; + + if (get_user(idx, &argp->offset)) + return -EFAULT; + + map = compat_alloc_user_space(sizeof(*map)); + if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + return -EFAULT; + if (__put_user(idx, &map->offset)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_GET_MAP, (unsigned long) map); + if (err) + return err; + + if (__get_user(m32.offset, &map->offset) + || __get_user(m32.size, &map->size) + || __get_user(m32.type, &map->type) + || __get_user(m32.flags, &map->flags) + || __get_user(handle, &map->handle) + || __get_user(m32.mtrr, &map->mtrr)) + return -EFAULT; + + m32.handle = (unsigned long) handle; + if (copy_to_user(argp, &m32, sizeof(m32))) + return -EFAULT; + return 0; + +} + +static int compat_drm_addmap(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_map32_t __user *argp = (void __user *)arg; + drm_map32_t m32; + drm_map_t __user *map; + int err; + void *handle; + + if (copy_from_user(&m32, argp, sizeof(m32))) + return -EFAULT; + + map = compat_alloc_user_space(sizeof(*map)); + if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + return -EFAULT; + if (__put_user(m32.offset, &map->offset) + || __put_user(m32.size, &map->size) + || __put_user(m32.type, &map->type) + || __put_user(m32.flags, &map->flags)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_ADD_MAP, (unsigned long) map); + if (err) + return err; + + if (__get_user(m32.offset, &map->offset) + || __get_user(m32.mtrr, &map->mtrr) + || __get_user(handle, &map->handle)) + return -EFAULT; + + m32.handle = (unsigned long) handle; + if (m32.handle != (unsigned long) handle && printk_ratelimit()) + printk(KERN_ERR "compat_drm_addmap truncated handle" + " %p for type %d offset %x\n", + handle, m32.type, m32.offset); + + if (copy_to_user(argp, &m32, sizeof(m32))) + return -EFAULT; + + return 0; +} + +static int compat_drm_rmmap(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_map32_t __user *argp = (void __user *)arg; + drm_map_t __user *map; + u32 handle; + + if (get_user(handle, &argp->handle)) + return -EFAULT; + + map = compat_alloc_user_space(sizeof(*map)); + if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + return -EFAULT; + if (__put_user((void *)(unsigned long) handle, &map->handle)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RM_MAP, (unsigned long) map); +} + +typedef struct drm_client32 { + int idx; /**< Which client desired? */ + int auth; /**< Is client authenticated? */ + u32 pid; /**< Process ID */ + u32 uid; /**< User ID */ + u32 magic; /**< Magic */ + u32 iocs; /**< Ioctl count */ +} drm_client32_t; + +static int compat_drm_getclient(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_client32_t c32; + drm_client32_t __user *argp = (void __user *)arg; + drm_client_t __user *client; + int idx, err; + + if (get_user(idx, &argp->idx)) + return -EFAULT; + + client = compat_alloc_user_space(sizeof(*client)); + if (!access_ok(VERIFY_WRITE, client, sizeof(*client))) + return -EFAULT; + if (__put_user(idx, &client->idx)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_GET_CLIENT, (unsigned long) client); + if (err) + return err; + + if (__get_user(c32.auth, &client->auth) + || __get_user(c32.pid, &client->pid) + || __get_user(c32.uid, &client->uid) + || __get_user(c32.magic, &client->magic) + || __get_user(c32.iocs, &client->iocs)) + return -EFAULT; + + if (copy_to_user(argp, &c32, sizeof(c32))) + return -EFAULT; + return 0; +} + +typedef struct drm_stats32 { + u32 count; + struct { + u32 value; + drm_stat_type_t type; + } data[15]; +} drm_stats32_t; + +static int compat_drm_getstats(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_stats32_t s32; + drm_stats32_t __user *argp = (void __user *)arg; + drm_stats_t __user *stats; + int i, err; + + stats = compat_alloc_user_space(sizeof(*stats)); + if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats))) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_GET_STATS, (unsigned long) stats); + if (err) + return err; + + if (__get_user(s32.count, &stats->count)) + return -EFAULT; + for (i = 0; i < 15; ++i) + if (__get_user(s32.data[i].value, &stats->data[i].value) + || __get_user(s32.data[i].type, &stats->data[i].type)) + return -EFAULT; + + if (copy_to_user(argp, &s32, sizeof(s32))) + return -EFAULT; + return 0; +} + +typedef struct drm_buf_desc32 { + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ + int flags; + u32 agp_start; /**< Start address in the AGP aperture */ +} drm_buf_desc32_t; + +static int compat_drm_addbufs(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_buf_desc32_t __user *argp = (void __user *)arg; + drm_buf_desc_t __user *buf; + int err; + unsigned long agp_start; + + buf = compat_alloc_user_space(sizeof(*buf)); + if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf)) + || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))) + return -EFAULT; + + if (__copy_in_user(buf, argp, offsetof(drm_buf_desc32_t, agp_start)) + || __get_user(agp_start, &argp->agp_start) + || __put_user(agp_start, &buf->agp_start)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_ADD_BUFS, (unsigned long) buf); + if (err) + return err; + + if (__copy_in_user(argp, buf, offsetof(drm_buf_desc32_t, agp_start)) + || __get_user(agp_start, &buf->agp_start) + || __put_user(agp_start, &argp->agp_start)) + return -EFAULT; + + return 0; +} + +static int compat_drm_markbufs(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_buf_desc32_t b32; + drm_buf_desc32_t __user *argp = (void __user *)arg; + drm_buf_desc_t __user *buf; + + if (copy_from_user(&b32, argp, sizeof(b32))) + return -EFAULT; + + buf = compat_alloc_user_space(sizeof(*buf)); + if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))) + return -EFAULT; + + if (__put_user(b32.size, &buf->size) + || __put_user(b32.low_mark, &buf->low_mark) + || __put_user(b32.high_mark, &buf->high_mark)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_MARK_BUFS, (unsigned long) buf); +} + +typedef struct drm_buf_info32 { + int count; /**< Entries in list */ + u32 list; +} drm_buf_info32_t; + +static int compat_drm_infobufs(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_buf_info32_t req32; + drm_buf_info32_t __user *argp = (void __user *)arg; + drm_buf_desc32_t __user *to; + drm_buf_info_t __user *request; + drm_buf_desc_t __user *list; + size_t nbytes; + int i, err; + int count, actual; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + + count = req32.count; + to = (drm_buf_desc32_t __user *)(unsigned long) req32.list; + if (count < 0) + count = 0; + if (count > 0 + && !access_ok(VERIFY_WRITE, to, count * sizeof(drm_buf_desc32_t))) + return -EFAULT; + + nbytes = sizeof(*request) + count * sizeof(drm_buf_desc_t); + request = compat_alloc_user_space(nbytes); + if (!access_ok(VERIFY_WRITE, request, nbytes)) + return -EFAULT; + list = (drm_buf_desc_t *) (request + 1); + + if (__put_user(count, &request->count) + || __put_user(list, &request->list)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_INFO_BUFS, (unsigned long) request); + if (err) + return err; + + if (__get_user(actual, &request->count)) + return -EFAULT; + if (count >= actual) + for (i = 0; i < actual; ++i) + if (__copy_in_user(&to[i], &list[i], + offsetof(drm_buf_desc_t, flags))) + return -EFAULT; + + if (__put_user(actual, &argp->count)) + return -EFAULT; + + return 0; +} + +typedef struct drm_buf_pub32 { + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + u32 address; /**< Address of buffer */ +} drm_buf_pub32_t; + +typedef struct drm_buf_map32 { + int count; /**< Length of the buffer list */ + u32 virtual; /**< Mmap'd area in user-virtual */ + u32 list; /**< Buffer information */ +} drm_buf_map32_t; + +static int compat_drm_mapbufs(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_buf_map32_t __user *argp = (void __user *)arg; + drm_buf_map32_t req32; + drm_buf_pub32_t __user *list32; + drm_buf_map_t __user *request; + drm_buf_pub_t __user *list; + int i, err; + int count, actual; + size_t nbytes; + void __user *addr; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + count = req32.count; + list32 = (void __user *)(unsigned long)req32.list; + + if (count < 0) + return -EINVAL; + nbytes = sizeof(*request) + count * sizeof(drm_buf_pub_t); + request = compat_alloc_user_space(nbytes); + if (!access_ok(VERIFY_WRITE, request, nbytes)) + return -EFAULT; + list = (drm_buf_pub_t *) (request + 1); + + if (__put_user(count, &request->count) + || __put_user(list, &request->list)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_MAP_BUFS, (unsigned long) request); + if (err) + return err; + + if (__get_user(actual, &request->count)) + return -EFAULT; + if (count >= actual) + for (i = 0; i < actual; ++i) + if (__copy_in_user(&list32[i], &list[i], + offsetof(drm_buf_pub_t, address)) + || __get_user(addr, &list[i].address) + || __put_user((unsigned long) addr, + &list32[i].address)) + return -EFAULT; + + if (__put_user(actual, &argp->count) + || __get_user(addr, &request->virtual) + || __put_user((unsigned long) addr, &argp->virtual)) + return -EFAULT; + + return 0; +} + +typedef struct drm_buf_free32 { + int count; + u32 list; +} drm_buf_free32_t; + +static int compat_drm_freebufs(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_buf_free32_t req32; + drm_buf_free_t __user *request; + drm_buf_free32_t __user *argp = (void __user *)arg; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + return -EFAULT; + if (__put_user(req32.count, &request->count) + || __put_user((int __user *)(unsigned long) req32.list, + &request->list)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_FREE_BUFS, (unsigned long) request); +} + +typedef struct drm_ctx_priv_map32 { + unsigned int ctx_id; /**< Context requesting private mapping */ + u32 handle; /**< Handle of map */ +} drm_ctx_priv_map32_t; + +static int compat_drm_setsareactx(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_priv_map32_t req32; + drm_ctx_priv_map_t __user *request; + drm_ctx_priv_map32_t __user *argp = (void __user *)arg; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + return -EFAULT; + if (__put_user(req32.ctx_id, &request->ctx_id) + || __put_user((void *)(unsigned long) req32.handle, + &request->handle)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_SET_SAREA_CTX, (unsigned long) request); +} + +static int compat_drm_getsareactx(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_priv_map_t __user *request; + drm_ctx_priv_map32_t __user *argp = (void __user *)arg; + int err; + unsigned int ctx_id; + void *handle; + + if (!access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + || __get_user(ctx_id, &argp->ctx_id)) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + return -EFAULT; + if (__put_user(ctx_id, &request->ctx_id)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_GET_SAREA_CTX, (unsigned long) request); + if (err) + return err; + + if (__get_user(handle, &request->handle) + || __put_user((unsigned long) handle, &argp->handle)) + return -EFAULT; + + return 0; +} + +typedef struct drm_ctx_res32 { + int count; + u32 contexts; +} drm_ctx_res32_t; + +static int compat_drm_resctx(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res32_t __user *argp = (void __user *)arg; + drm_ctx_res32_t res32; + drm_ctx_res_t __user *res; + int err; + + if (copy_from_user(&res32, argp, sizeof(res32))) + return -EFAULT; + + res = compat_alloc_user_space(sizeof(*res)); + if (!access_ok(VERIFY_WRITE, res, sizeof(*res))) + return -EFAULT; + if (__put_user(res32.count, &res->count) + || __put_user((drm_ctx_t __user *)(unsigned long) res32.contexts, + &res->contexts)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RES_CTX, (unsigned long) res); + if (err) + return err; + + if (__get_user(res32.count, &res->count) + || __put_user(res32.count, &argp->count)) + return -EFAULT; + + return 0; +} + +typedef struct drm_dma32 { + int context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + u32 send_indices; /**< List of handles to buffers */ + u32 send_sizes; /**< Lengths of data to send */ + drm_dma_flags_t flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size for buffers */ + u32 request_indices; /**< Buffer information */ + u32 request_sizes; + int granted_count; /**< Number of buffers granted */ +} drm_dma32_t; + +static int compat_drm_dma(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_dma32_t d32; + drm_dma32_t __user *argp = (void __user *) arg; + drm_dma_t __user *d; + int err; + + if (copy_from_user(&d32, argp, sizeof(d32))) + return -EFAULT; + + d = compat_alloc_user_space(sizeof(*d)); + if (!access_ok(VERIFY_WRITE, d, sizeof(*d))) + return -EFAULT; + + if (__put_user(d32.context, &d->context) + || __put_user(d32.send_count, &d->send_count) + || __put_user((int __user *)(unsigned long) d32.send_indices, + &d->send_indices) + || __put_user((int __user *)(unsigned long) d32.send_sizes, + &d->send_sizes) + || __put_user(d32.flags, &d->flags) + || __put_user(d32.request_count, &d->request_count) + || __put_user((int __user *)(unsigned long) d32.request_indices, + &d->request_indices) + || __put_user((int __user *)(unsigned long) d32.request_sizes, + &d->request_sizes)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_DMA, (unsigned long) d); + if (err) + return err; + + if (__get_user(d32.request_size, &d->request_size) + || __get_user(d32.granted_count, &d->granted_count) + || __put_user(d32.request_size, &argp->request_size) + || __put_user(d32.granted_count, &argp->granted_count)) + return -EFAULT; + + return 0; +} + +#if __OS_HAS_AGP +typedef struct drm_agp_mode32 { + u32 mode; /**< AGP mode */ +} drm_agp_mode32_t; + +static int compat_drm_agp_enable(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_agp_mode32_t __user *argp = (void __user *)arg; + drm_agp_mode32_t m32; + drm_agp_mode_t __user *mode; + + if (get_user(m32.mode, &argp->mode)) + return -EFAULT; + + mode = compat_alloc_user_space(sizeof(*mode)); + if (put_user(m32.mode, &mode->mode)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_ENABLE, (unsigned long) mode); +} + +typedef struct drm_agp_info32 { + int agp_version_major; + int agp_version_minor; + u32 mode; + u32 aperture_base; /* physical address */ + u32 aperture_size; /* bytes */ + u32 memory_allowed; /* bytes */ + u32 memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +} drm_agp_info32_t; + +static int compat_drm_agp_info(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_agp_info32_t __user *argp = (void __user *)arg; + drm_agp_info32_t i32; + drm_agp_info_t __user *info; + int err; + + info = compat_alloc_user_space(sizeof(*info)); + if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_INFO, (unsigned long) info); + if (err) + return err; + + if (__get_user(i32.agp_version_major, &info->agp_version_major) + || __get_user(i32.agp_version_minor, &info->agp_version_minor) + || __get_user(i32.mode, &info->mode) + || __get_user(i32.aperture_base, &info->aperture_base) + || __get_user(i32.aperture_size, &info->aperture_size) + || __get_user(i32.memory_allowed, &info->memory_allowed) + || __get_user(i32.memory_used, &info->memory_used) + || __get_user(i32.id_vendor, &info->id_vendor) + || __get_user(i32.id_device, &info->id_device)) + return -EFAULT; + + if (copy_to_user(argp, &i32, sizeof(i32))) + return -EFAULT; + + return 0; +} + +typedef struct drm_agp_buffer32 { + u32 size; /**< In bytes -- will round to page boundary */ + u32 handle; /**< Used for binding / unbinding */ + u32 type; /**< Type of memory to allocate */ + u32 physical; /**< Physical used by i810 */ +} drm_agp_buffer32_t; + +static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_agp_buffer32_t __user *argp = (void __user *)arg; + drm_agp_buffer32_t req32; + drm_agp_buffer_t __user *request; + int err; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.size, &request->size) + || __put_user(req32.type, &request->type)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_ALLOC, (unsigned long) request); + if (err) + return err; + + if (__get_user(req32.handle, &request->handle) + || __get_user(req32.physical, &request->physical) + || copy_to_user(argp, &req32, sizeof(req32))) { + drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_FREE, (unsigned long) request); + return -EFAULT; + } + + return 0; +} + +static int compat_drm_agp_free(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_agp_buffer32_t __user *argp = (void __user *)arg; + drm_agp_buffer_t __user *request; + u32 handle; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || get_user(handle, &argp->handle) + || __put_user(handle, &request->handle)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_FREE, (unsigned long) request); +} + +typedef struct drm_agp_binding32 { + u32 handle; /**< From drm_agp_buffer */ + u32 offset; /**< In bytes -- will round to page boundary */ +} drm_agp_binding32_t; + +static int compat_drm_agp_bind(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_agp_binding32_t __user *argp = (void __user *)arg; + drm_agp_binding32_t req32; + drm_agp_binding_t __user *request; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.handle, &request->handle) + || __put_user(req32.offset, &request->offset)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_BIND, (unsigned long) request); +} + +static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_agp_binding32_t __user *argp = (void __user *)arg; + drm_agp_binding_t __user *request; + u32 handle; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || get_user(handle, &argp->handle) + || __put_user(handle, &request->handle)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_AGP_UNBIND, (unsigned long) request); +} +#endif /* __OS_HAS_AGP */ + +typedef struct drm_scatter_gather32 { + u32 size; /**< In bytes -- will round to page boundary */ + u32 handle; /**< Used for mapping / unmapping */ +} drm_scatter_gather32_t; + +static int compat_drm_sg_alloc(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_scatter_gather32_t __user *argp = (void __user *)arg; + drm_scatter_gather_t __user *request; + int err; + unsigned long x; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + || __get_user(x, &argp->size) + || __put_user(x, &request->size)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_SG_ALLOC, (unsigned long) request); + if (err) + return err; + + /* XXX not sure about the handle conversion here... */ + if (__get_user(x, &request->handle) + || __put_user(x >> PAGE_SHIFT, &argp->handle)) + return -EFAULT; + + return 0; +} + +static int compat_drm_sg_free(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_scatter_gather32_t __user *argp = (void __user *)arg; + drm_scatter_gather_t __user *request; + unsigned long x; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + || __get_user(x, &argp->handle) + || __put_user(x << PAGE_SHIFT, &request->handle)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_SG_FREE, (unsigned long) request); +} + +struct drm_wait_vblank_request32 { + drm_vblank_seq_type_t type; + unsigned int sequence; + u32 signal; +}; + +struct drm_wait_vblank_reply32 { + drm_vblank_seq_type_t type; + unsigned int sequence; + s32 tval_sec; + s32 tval_usec; +}; + +typedef union drm_wait_vblank32 { + struct drm_wait_vblank_request32 request; + struct drm_wait_vblank_reply32 reply; +} drm_wait_vblank32_t; + +static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_wait_vblank32_t __user *argp = (void __user *)arg; + drm_wait_vblank32_t req32; + drm_wait_vblank_t __user *request; + int err; + + if (copy_from_user(&req32, argp, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.request.type, &request->request.type) + || __put_user(req32.request.sequence, &request->request.sequence) + || __put_user(req32.request.signal, &request->request.signal)) + return -EFAULT; + + err = drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_WAIT_VBLANK, (unsigned long) request); + if (err) + return err; + + if (__get_user(req32.reply.type, &request->reply.type) + || __get_user(req32.reply.sequence, &request->reply.sequence) + || __get_user(req32.reply.tval_sec, &request->reply.tval_sec) + || __get_user(req32.reply.tval_usec, &request->reply.tval_usec)) + return -EFAULT; + + if (copy_to_user(argp, &req32, sizeof(req32))) + return -EFAULT; + + return 0; +} + +drm_ioctl_compat_t *drm_compat_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT32)] = compat_drm_getclient, + [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS32)] = compat_drm_getstats, + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE32)] = compat_drm_setunique, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP32)] = compat_drm_addmap, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS32)] = compat_drm_addbufs, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS32)] = compat_drm_markbufs, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS32)] = compat_drm_infobufs, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS32)] = compat_drm_mapbufs, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS32)] = compat_drm_freebufs, + [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP32)] = compat_drm_rmmap, + [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX32)] = compat_drm_setsareactx, + [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX32)] = compat_drm_getsareactx, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX32)] = compat_drm_resctx, + [DRM_IOCTL_NR(DRM_IOCTL_DMA32)] = compat_drm_dma, +#if __OS_HAS_AGP + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE32)] = compat_drm_agp_enable, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO32)] = compat_drm_agp_info, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC32)] = compat_drm_agp_alloc, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE32)] = compat_drm_agp_free, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND32)] = compat_drm_agp_bind, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND32)] = compat_drm_agp_unbind, +#endif + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc, + [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free, + [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank, +}; + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/drm. + * + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn; + int ret; + + if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls)) + return -ENOTTY; + + fn = drm_compat_ioctls[nr]; + + lock_kernel(); /* XXX for now */ + if (fn != NULL) + ret = (*fn)(filp, cmd, arg); + else + ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + + return ret; +} +EXPORT_SYMBOL(drm_compat_ioctl); diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 7300a09..b5903f9 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -1,10 +1,30 @@ /* i915_dma.c -- DMA support for the I915 -*- linux-c -*- */ /************************************************************************** - * + * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************/ #include "drmP.h" diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h index 7e55edf..23e027d 100644 --- a/drivers/char/drm/i915_drm.h +++ b/drivers/char/drm/i915_drm.h @@ -1,3 +1,30 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #ifndef _I915_DRM_H_ #define _I915_DRM_H_ diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index 002b708..e6a9e1d 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -1,11 +1,30 @@ /* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- */ - /************************************************************************** - * + * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************/ #include "drmP.h" diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index f6ca92a..fa940d6 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -1,10 +1,30 @@ /* i915_drv.h -- Private header for the I915 driver -*- linux-c -*- */ /************************************************************************** - * + * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************/ #ifndef _I915_DRV_H_ diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index b023926..a101cc9 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -1,10 +1,30 @@ /* i915_dma.c -- DMA support for the I915 -*- linux-c -*- */ /************************************************************************** - * + * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************/ #include "drmP.h" diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c index d54a300..9b1698f 100644 --- a/drivers/char/drm/i915_mem.c +++ b/drivers/char/drm/i915_mem.c @@ -1,10 +1,30 @@ /* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*- */ /************************************************************************** - * + * * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************/ #include "drmP.h" diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c index 7b983d9..18e4e5b 100644 --- a/drivers/char/drm/radeon_drv.c +++ b/drivers/char/drm/radeon_drv.c @@ -101,6 +101,9 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = radeon_compat_ioctl, +#endif }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 5837098..771aa80 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -317,6 +317,9 @@ extern int radeon_preinit( struct drm_device *dev, unsigned long flags ); extern int radeon_postinit( struct drm_device *dev, unsigned long flags ); extern int radeon_postcleanup( struct drm_device *dev ); +extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); + /* Flags for stats.boxes */ #define RADEON_BOX_DMA_IDLE 0x1 diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c new file mode 100644 index 0000000..bfe6122 --- /dev/null +++ b/drivers/char/drm/radeon_ioc32.c @@ -0,0 +1,395 @@ +/** + * \file radeon_ioc32.c + * + * 32-bit ioctl compatibility routines for the Radeon DRM. + * + * \author Paul Mackerras <paulus@samba.org> + * + * Copyright (C) Paul Mackerras 2005 + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <linux/compat.h> +#include <linux/ioctl32.h> + +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +typedef struct drm_radeon_init32 { + int func; + u32 sarea_priv_offset; + int is_pci; + int cp_mode; + int gart_size; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + u32 fb_offset; + u32 mmio_offset; + u32 ring_offset; + u32 ring_rptr_offset; + u32 buffers_offset; + u32 gart_textures_offset; +} drm_radeon_init32_t; + +static int compat_radeon_cp_init(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_init32_t init32; + drm_radeon_init_t __user *init; + + if (copy_from_user(&init32, (void __user *)arg, sizeof(init32))) + return -EFAULT; + + init = compat_alloc_user_space(sizeof(*init)); + if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) + || __put_user(init32.func, &init->func) + || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) + || __put_user(init32.is_pci, &init->is_pci) + || __put_user(init32.cp_mode, &init->cp_mode) + || __put_user(init32.gart_size, &init->gart_size) + || __put_user(init32.ring_size, &init->ring_size) + || __put_user(init32.usec_timeout, &init->usec_timeout) + || __put_user(init32.fb_bpp, &init->fb_bpp) + || __put_user(init32.front_offset, &init->front_offset) + || __put_user(init32.front_pitch, &init->front_pitch) + || __put_user(init32.back_offset, &init->back_offset) + || __put_user(init32.back_pitch, &init->back_pitch) + || __put_user(init32.depth_bpp, &init->depth_bpp) + || __put_user(init32.depth_offset, &init->depth_offset) + || __put_user(init32.depth_pitch, &init->depth_pitch) + || __put_user(init32.fb_offset, &init->fb_offset) + || __put_user(init32.mmio_offset, &init->mmio_offset) + || __put_user(init32.ring_offset, &init->ring_offset) + || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset) + || __put_user(init32.buffers_offset, &init->buffers_offset) + || __put_user(init32.gart_textures_offset, + &init->gart_textures_offset)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_CP_INIT, (unsigned long) init); +} + +typedef struct drm_radeon_clear32 { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; /* misnamed field: should be stencil */ + u32 depth_boxes; +} drm_radeon_clear32_t; + +static int compat_radeon_cp_clear(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_clear32_t clr32; + drm_radeon_clear_t __user *clr; + + if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32))) + return -EFAULT; + + clr = compat_alloc_user_space(sizeof(*clr)); + if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr)) + || __put_user(clr32.flags, &clr->flags) + || __put_user(clr32.clear_color, &clr->clear_color) + || __put_user(clr32.clear_depth, &clr->clear_depth) + || __put_user(clr32.color_mask, &clr->color_mask) + || __put_user(clr32.depth_mask, &clr->depth_mask) + || __put_user((void __user *)(unsigned long)clr32.depth_boxes, + &clr->depth_boxes)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_CLEAR, (unsigned long) clr); +} + +typedef struct drm_radeon_stipple32 { + u32 mask; +} drm_radeon_stipple32_t; + +static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_stipple32_t __user *argp = (void __user *) arg; + drm_radeon_stipple_t __user *request; + u32 mask; + + if (get_user(mask, &argp->mask)) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user((unsigned int __user *)(unsigned long) mask, + &request->mask)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_STIPPLE, (unsigned long) request); +} + +typedef struct drm_radeon_tex_image32 { + unsigned int x, y; /* Blit coordinates */ + unsigned int width, height; + u32 data; +} drm_radeon_tex_image32_t; + +typedef struct drm_radeon_texture32 { + unsigned int offset; + int pitch; + int format; + int width; /* Texture image coordinates */ + int height; + u32 image; +} drm_radeon_texture32_t; + +static int compat_radeon_cp_texture(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_texture32_t req32; + drm_radeon_texture_t __user *request; + drm_radeon_tex_image32_t img32; + drm_radeon_tex_image_t __user *image; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + if (req32.image == 0) + return -EINVAL; + if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image, + sizeof(img32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request) + sizeof(*image)); + if (!access_ok(VERIFY_WRITE, request, + sizeof(*request) + sizeof(*image))) + return -EFAULT; + image = (drm_radeon_tex_image_t __user *) (request + 1); + + if (__put_user(req32.offset, &request->offset) + || __put_user(req32.pitch, &request->pitch) + || __put_user(req32.format, &request->format) + || __put_user(req32.width, &request->width) + || __put_user(req32.height, &request->height) + || __put_user(image, &request->image) + || __put_user(img32.x, &image->x) + || __put_user(img32.y, &image->y) + || __put_user(img32.width, &image->width) + || __put_user(img32.height, &image->height) + || __put_user((const void __user *)(unsigned long)img32.data, + &image->data)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_TEXTURE, (unsigned long) request); +} + +typedef struct drm_radeon_vertex2_32 { + int idx; /* Index of vertex buffer */ + int discard; /* Client finished with buffer? */ + int nr_states; + u32 state; + int nr_prims; + u32 prim; +} drm_radeon_vertex2_32_t; + +static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_vertex2_32_t req32; + drm_radeon_vertex2_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.idx, &request->idx) + || __put_user(req32.discard, &request->discard) + || __put_user(req32.nr_states, &request->nr_states) + || __put_user((void __user *)(unsigned long)req32.state, + &request->state) + || __put_user(req32.nr_prims, &request->nr_prims) + || __put_user((void __user *)(unsigned long)req32.prim, + &request->prim)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_VERTEX2, (unsigned long) request); +} + +typedef struct drm_radeon_cmd_buffer32 { + int bufsz; + u32 buf; + int nbox; + u32 boxes; +} drm_radeon_cmd_buffer32_t; + +static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_cmd_buffer32_t req32; + drm_radeon_cmd_buffer_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.bufsz, &request->bufsz) + || __put_user((void __user *)(unsigned long)req32.buf, + &request->buf) + || __put_user(req32.nbox, &request->nbox) + || __put_user((void __user *)(unsigned long)req32.boxes, + &request->boxes)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_CMDBUF, (unsigned long) request); +} + +typedef struct drm_radeon_getparam32 { + int param; + u32 value; +} drm_radeon_getparam32_t; + +static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_getparam32_t req32; + drm_radeon_getparam_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.param, &request->param) + || __put_user((void __user *)(unsigned long)req32.value, + &request->value)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_GETPARAM, (unsigned long) request); +} + +typedef struct drm_radeon_mem_alloc32 { + int region; + int alignment; + int size; + u32 region_offset; /* offset from start of fb or GART */ +} drm_radeon_mem_alloc32_t; + +static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_mem_alloc32_t req32; + drm_radeon_mem_alloc_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.region, &request->region) + || __put_user(req32.alignment, &request->alignment) + || __put_user(req32.size, &request->size) + || __put_user((int __user *)(unsigned long)req32.region_offset, + &request->region_offset)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_ALLOC, (unsigned long) request); +} + +typedef struct drm_radeon_irq_emit32 { + u32 irq_seq; +} drm_radeon_irq_emit32_t; + +static int compat_radeon_irq_emit(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_radeon_irq_emit32_t req32; + drm_radeon_irq_emit_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user((int __user *)(unsigned long)req32.irq_seq, + &request->irq_seq)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long) request); +} + +drm_ioctl_compat_t *radeon_compat_ioctls[] = { + [DRM_RADEON_CP_INIT] = compat_radeon_cp_init, + [DRM_RADEON_CLEAR] = compat_radeon_cp_clear, + [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple, + [DRM_RADEON_TEXTURE] = compat_radeon_cp_texture, + [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2, + [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf, + [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam, + [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc, + [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit, +}; + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card<n>. + * + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long radeon_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn = NULL; + int ret; + + if (nr < DRM_COMMAND_BASE) + return drm_compat_ioctl(filp, cmd, arg); + + if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls)) + fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE]; + + lock_kernel(); /* XXX for now */ + if (fn != NULL) + ret = (*fn)(filp, cmd, arg); + else + ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + + return ret; +} diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index cd25f28..40474a6 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -35,6 +35,14 @@ #include "radeon_drm.h" #include "radeon_drv.h" +static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 mask) +{ + u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; + if (irqs) + RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); + return irqs; +} + /* Interrupts - Used for device synchronization and flushing in the * following circumstances: * @@ -63,8 +71,8 @@ irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ) /* Only consider the bits we're interested in - others could be used * outside the DRM */ - stat = RADEON_READ(RADEON_GEN_INT_STATUS) - & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT); + stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | + RADEON_CRTC_VBLANK_STAT)); if (!stat) return IRQ_NONE; @@ -80,19 +88,9 @@ irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ) drm_vbl_send_signals( dev ); } - /* Acknowledge interrupts we handle */ - RADEON_WRITE(RADEON_GEN_INT_STATUS, stat); return IRQ_HANDLED; } -static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv) -{ - u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS ) - & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT); - if (tmp) - RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); -} - static int radeon_emit_irq(drm_device_t *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -141,7 +139,7 @@ int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) return DRM_ERR(EINVAL); } - radeon_acknowledge_irqs( dev_priv ); + radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT); dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; @@ -219,7 +217,8 @@ void radeon_driver_irq_preinstall( drm_device_t *dev ) { RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); /* Clear bits if they're already high */ - radeon_acknowledge_irqs( dev_priv ); + radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | + RADEON_CRTC_VBLANK_STAT)); } void radeon_driver_irq_postinstall( drm_device_t *dev ) { diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 7def6ad..62cda25 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -163,8 +163,7 @@ static void ds1620_out(int cmd, int bits, int value) netwinder_ds1620_reset(); netwinder_unlock(&flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2); + msleep(20); } static unsigned int ds1620_in(int cmd, int bits) diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c index 220a227..65ffc0b 100644 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ b/drivers/char/ftape/compressor/zftape-compress.c @@ -1176,8 +1176,8 @@ KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); } #else /* !MODULE */ /* print a short no-nonsense boot message */ - printk("zftape compressor v1.00a 970514\n"); - printk("For use with " FTAPE_VERSION "\n"); + printk(KERN_INFO "zftape compressor v1.00a 970514\n"); + printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); #endif /* MODULE */ TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); TRACE(ft_t_info, "installing compressor for zftape ..."); diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5ec732e..762fa43 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -834,7 +834,7 @@ int hpet_alloc(struct hpet_data *hdp) printk("\n"); ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ - do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */ + ns /= 1000000; /* convert to nanoseconds, 10^-9 */ printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", hpetp->hp_which, ns, hpetp->hp_ntimer, cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index a811976..6c4b3f9 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -20,13 +20,14 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/proc_fs.h> -#include <linux/apm_bios.h> +#include <linux/seq_file.h> +#include <linux/dmi.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/i8k.h> -#define I8K_VERSION "1.13 14/05/2002" +#define I8K_VERSION "1.14 21/02/2005" #define I8K_SMM_FN_STATUS 0x0025 #define I8K_SMM_POWER_STATUS 0x0069 @@ -34,7 +35,8 @@ #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 #define I8K_SMM_GET_TEMP 0x10a3 -#define I8K_SMM_GET_DELL_SIG 0xffa3 +#define I8K_SMM_GET_DELL_SIG1 0xfea3 +#define I8K_SMM_GET_DELL_SIG2 0xffa3 #define I8K_SMM_BIOS_VERSION 0x00a6 #define I8K_FAN_MULT 30 @@ -52,18 +54,7 @@ #define I8K_TEMPERATURE_BUG 1 -#define DELL_SIGNATURE "Dell Computer" - -static char *supported_models[] = { - "Inspiron", - "Latitude", - NULL -}; - -static char system_vendor[48] = "?"; -static char product_name [48] = "?"; -static char bios_version [4] = "?"; -static char serial_number[16] = "?"; +static char bios_version[4]; MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); @@ -73,6 +64,10 @@ static int force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force loading without checking for supported models"); +static int ignore_dmi; +module_param(ignore_dmi, bool, 0); +MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); + static int restricted; module_param(restricted, bool, 0); MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); @@ -81,69 +76,69 @@ static int power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); -static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *); +static int i8k_open_fs(struct inode *inode, struct file *file); static int i8k_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static struct file_operations i8k_fops = { - .read = i8k_read, - .ioctl = i8k_ioctl, + .open = i8k_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .ioctl = i8k_ioctl, +}; + +struct smm_regs { + unsigned int eax; + unsigned int ebx __attribute__ ((packed)); + unsigned int ecx __attribute__ ((packed)); + unsigned int edx __attribute__ ((packed)); + unsigned int esi __attribute__ ((packed)); + unsigned int edi __attribute__ ((packed)); }; -typedef struct { - unsigned int eax; - unsigned int ebx __attribute__ ((packed)); - unsigned int ecx __attribute__ ((packed)); - unsigned int edx __attribute__ ((packed)); - unsigned int esi __attribute__ ((packed)); - unsigned int edi __attribute__ ((packed)); -} SMMRegisters; - -typedef struct { - u8 type; - u8 length; - u16 handle; -} DMIHeader; +static inline char *i8k_get_dmi_data(int field) +{ + return dmi_get_system_info(field) ? : "N/A"; +} /* * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. */ -static int i8k_smm(SMMRegisters *regs) +static int i8k_smm(struct smm_regs *regs) { - int rc; - int eax = regs->eax; - - asm("pushl %%eax\n\t" \ - "movl 0(%%eax),%%edx\n\t" \ - "push %%edx\n\t" \ - "movl 4(%%eax),%%ebx\n\t" \ - "movl 8(%%eax),%%ecx\n\t" \ - "movl 12(%%eax),%%edx\n\t" \ - "movl 16(%%eax),%%esi\n\t" \ - "movl 20(%%eax),%%edi\n\t" \ - "popl %%eax\n\t" \ - "out %%al,$0xb2\n\t" \ - "out %%al,$0x84\n\t" \ - "xchgl %%eax,(%%esp)\n\t" - "movl %%ebx,4(%%eax)\n\t" \ - "movl %%ecx,8(%%eax)\n\t" \ - "movl %%edx,12(%%eax)\n\t" \ - "movl %%esi,16(%%eax)\n\t" \ - "movl %%edi,20(%%eax)\n\t" \ - "popl %%edx\n\t" \ - "movl %%edx,0(%%eax)\n\t" \ - "lahf\n\t" \ - "shrl $8,%%eax\n\t" \ - "andl $1,%%eax\n" \ - : "=a" (rc) - : "a" (regs) - : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); - - if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { - return -EINVAL; - } - - return 0; + int rc; + int eax = regs->eax; + + asm("pushl %%eax\n\t" + "movl 0(%%eax),%%edx\n\t" + "push %%edx\n\t" + "movl 4(%%eax),%%ebx\n\t" + "movl 8(%%eax),%%ecx\n\t" + "movl 12(%%eax),%%edx\n\t" + "movl 16(%%eax),%%esi\n\t" + "movl 20(%%eax),%%edi\n\t" + "popl %%eax\n\t" + "out %%al,$0xb2\n\t" + "out %%al,$0x84\n\t" + "xchgl %%eax,(%%esp)\n\t" + "movl %%ebx,4(%%eax)\n\t" + "movl %%ecx,8(%%eax)\n\t" + "movl %%edx,12(%%eax)\n\t" + "movl %%esi,16(%%eax)\n\t" + "movl %%edi,20(%%eax)\n\t" + "popl %%edx\n\t" + "movl %%edx,0(%%eax)\n\t" + "lahf\n\t" + "shrl $8,%%eax\n\t" + "andl $1,%%eax\n":"=a"(rc) + : "a"(regs) + : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); + + if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) + return -EINVAL; + + return 0; } /* @@ -152,24 +147,9 @@ static int i8k_smm(SMMRegisters *regs) */ static int i8k_get_bios_version(void) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_BIOS_VERSION; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - return regs.eax; -} + struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, }; -/* - * Read the machine id. - */ -static int i8k_get_serial_number(unsigned char *buff) -{ - strlcpy(buff, serial_number, sizeof(serial_number)); - return 0; + return i8k_smm(®s) ? : regs.eax; } /* @@ -177,24 +157,22 @@ static int i8k_get_serial_number(unsigned char *buff) */ static int i8k_get_fn_status(void) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_FN_STATUS; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { - case I8K_FN_UP: - return I8K_VOL_UP; - case I8K_FN_DOWN: - return I8K_VOL_DOWN; - case I8K_FN_MUTE: - return I8K_VOL_MUTE; - default: - return 0; - } + struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, }; + int rc; + + if ((rc = i8k_smm(®s)) < 0) + return rc; + + switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { + case I8K_FN_UP: + return I8K_VOL_UP; + case I8K_FN_DOWN: + return I8K_VOL_DOWN; + case I8K_FN_MUTE: + return I8K_VOL_MUTE; + default: + return 0; + } } /* @@ -202,20 +180,13 @@ static int i8k_get_fn_status(void) */ static int i8k_get_power_status(void) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_POWER_STATUS; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - switch (regs.eax & 0xff) { - case I8K_POWER_AC: - return I8K_AC; - default: - return I8K_BATTERY; - } + struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, }; + int rc; + + if ((rc = i8k_smm(®s)) < 0) + return rc; + + return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; } /* @@ -223,16 +194,10 @@ static int i8k_get_power_status(void) */ static int i8k_get_fan_status(int fan) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_GET_FAN; - regs.ebx = fan & 0xff; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } + struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; - return (regs.eax & 0xff); + regs.ebx = fan & 0xff; + return i8k_smm(®s) ? : regs.eax & 0xff; } /* @@ -240,16 +205,10 @@ static int i8k_get_fan_status(int fan) */ static int i8k_get_fan_speed(int fan) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; + struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; - regs.eax = I8K_SMM_GET_SPEED; - regs.ebx = fan & 0xff; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - return (regs.eax & 0xffff) * I8K_FAN_MULT; + regs.ebx = fan & 0xff; + return i8k_smm(®s) ? : (regs.eax & 0xffff) * I8K_FAN_MULT; } /* @@ -257,532 +216,318 @@ static int i8k_get_fan_speed(int fan) */ static int i8k_set_fan(int fan, int speed) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); + struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; - regs.eax = I8K_SMM_SET_FAN; - regs.ebx = (fan & 0xff) | (speed << 8); - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } + speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); + regs.ebx = (fan & 0xff) | (speed << 8); - return (i8k_get_fan_status(fan)); + return i8k_smm(®s) ? : i8k_get_fan_status(fan); } /* * Read the cpu temperature. */ -static int i8k_get_cpu_temp(void) +static int i8k_get_temp(int sensor) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - int temp; + struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, }; + int rc; + int temp; #ifdef I8K_TEMPERATURE_BUG - static int prev = 0; + static int prev; #endif + regs.ebx = sensor & 0xff; + if ((rc = i8k_smm(®s)) < 0) + return rc; - regs.eax = I8K_SMM_GET_TEMP; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - temp = regs.eax & 0xff; + temp = regs.eax & 0xff; #ifdef I8K_TEMPERATURE_BUG - /* - * Sometimes the temperature sensor returns 0x99, which is out of range. - * In this case we return (once) the previous cached value. For example: - # 1003655137 00000058 00005a4b - # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees - # 1003655139 00000054 00005c52 - */ - if (temp > I8K_MAX_TEMP) { - temp = prev; - prev = I8K_MAX_TEMP; - } else { - prev = temp; - } + /* + * Sometimes the temperature sensor returns 0x99, which is out of range. + * In this case we return (once) the previous cached value. For example: + # 1003655137 00000058 00005a4b + # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees + # 1003655139 00000054 00005c52 + */ + if (temp > I8K_MAX_TEMP) { + temp = prev; + prev = I8K_MAX_TEMP; + } else { + prev = temp; + } #endif - return temp; + return temp; } -static int i8k_get_dell_signature(void) +static int i8k_get_dell_signature(int req_fn) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; + struct smm_regs regs = { .eax = req_fn, }; + int rc; - regs.eax = I8K_SMM_GET_DELL_SIG; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } + if ((rc = i8k_smm(®s)) < 0) + return rc; - if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) { - return 0; - } else { - return -1; - } + return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; } static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { - int val; - int speed; - unsigned char buff[16]; - int __user *argp = (int __user *)arg; - - if (!argp) - return -EINVAL; - - switch (cmd) { - case I8K_BIOS_VERSION: - val = i8k_get_bios_version(); - break; - - case I8K_MACHINE_ID: - memset(buff, 0, 16); - val = i8k_get_serial_number(buff); - break; - - case I8K_FN_STATUS: - val = i8k_get_fn_status(); - break; - - case I8K_POWER_STATUS: - val = i8k_get_power_status(); - break; - - case I8K_GET_TEMP: - val = i8k_get_cpu_temp(); - break; - - case I8K_GET_SPEED: - if (copy_from_user(&val, argp, sizeof(int))) { - return -EFAULT; - } - val = i8k_get_fan_speed(val); - break; - - case I8K_GET_FAN: - if (copy_from_user(&val, argp, sizeof(int))) { - return -EFAULT; - } - val = i8k_get_fan_status(val); - break; + int val = 0; + int speed; + unsigned char buff[16]; + int __user *argp = (int __user *)arg; - case I8K_SET_FAN: - if (restricted && !capable(CAP_SYS_ADMIN)) { - return -EPERM; - } - if (copy_from_user(&val, argp, sizeof(int))) { - return -EFAULT; - } - if (copy_from_user(&speed, argp+1, sizeof(int))) { - return -EFAULT; - } - val = i8k_set_fan(val, speed); - break; + if (!argp) + return -EINVAL; - default: - return -EINVAL; - } + switch (cmd) { + case I8K_BIOS_VERSION: + val = i8k_get_bios_version(); + break; - if (val < 0) { - return val; - } + case I8K_MACHINE_ID: + memset(buff, 0, 16); + strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff)); + break; - switch (cmd) { - case I8K_BIOS_VERSION: - if (copy_to_user(argp, &val, 4)) { - return -EFAULT; - } - break; - case I8K_MACHINE_ID: - if (copy_to_user(argp, buff, 16)) { - return -EFAULT; - } - break; - default: - if (copy_to_user(argp, &val, sizeof(int))) { - return -EFAULT; - } - break; - } + case I8K_FN_STATUS: + val = i8k_get_fn_status(); + break; - return 0; -} + case I8K_POWER_STATUS: + val = i8k_get_power_status(); + break; -/* - * Print the information for /proc/i8k. - */ -static int i8k_get_info(char *buffer, char **start, off_t fpos, int length) -{ - int n, fn_key, cpu_temp, ac_power; - int left_fan, right_fan, left_speed, right_speed; - - cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */ - left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ - right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ - left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ - right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ - fn_key = i8k_get_fn_status(); /* 750 µs */ - if (power_status) { - ac_power = i8k_get_power_status(); /* 14700 µs */ - } else { - ac_power = -1; - } - - /* - * Info: - * - * 1) Format version (this will change if format changes) - * 2) BIOS version - * 3) BIOS machine ID - * 4) Cpu temperature - * 5) Left fan status - * 6) Right fan status - * 7) Left fan speed - * 8) Right fan speed - * 9) AC power - * 10) Fn Key status - */ - n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n", - I8K_PROC_FMT, - bios_version, - serial_number, - cpu_temp, - left_fan, - right_fan, - left_speed, - right_speed, - ac_power, - fn_key); - - return n; -} + case I8K_GET_TEMP: + val = i8k_get_temp(0); + break; -static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos) -{ - int n; - char info[128]; + case I8K_GET_SPEED: + if (copy_from_user(&val, argp, sizeof(int))) + return -EFAULT; - n = i8k_get_info(info, NULL, 0, 128); - if (n <= 0) { - return n; - } + val = i8k_get_fan_speed(val); + break; - if (*fpos >= n) { - return 0; - } + case I8K_GET_FAN: + if (copy_from_user(&val, argp, sizeof(int))) + return -EFAULT; - if ((*fpos + len) >= n) { - len = n - *fpos; - } + val = i8k_get_fan_status(val); + break; - if (copy_to_user(buffer, info, len) != 0) { - return -EFAULT; - } + case I8K_SET_FAN: + if (restricted && !capable(CAP_SYS_ADMIN)) + return -EPERM; - *fpos += len; - return len; -} + if (copy_from_user(&val, argp, sizeof(int))) + return -EFAULT; -static char* __init string_trim(char *s, int size) -{ - int len; - char *p; + if (copy_from_user(&speed, argp + 1, sizeof(int))) + return -EFAULT; - if ((len = strlen(s)) > size) { - len = size; - } + val = i8k_set_fan(val, speed); + break; - for (p=s+len-1; len && (*p==' '); len--,p--) { - *p = '\0'; - } + default: + return -EINVAL; + } - return s; -} + if (val < 0) + return val; -/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */ + switch (cmd) { + case I8K_BIOS_VERSION: + if (copy_to_user(argp, &val, 4)) + return -EFAULT; -/* - * |<-- dmi->length -->| - * | | - * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0 - * | | - * +-----------------------+ - */ -static char* __init dmi_string(DMIHeader *dmi, u8 s) -{ - u8 *p; + break; + case I8K_MACHINE_ID: + if (copy_to_user(argp, buff, 16)) + return -EFAULT; - if (!s) { - return ""; - } - s--; + break; + default: + if (copy_to_user(argp, &val, sizeof(int))) + return -EFAULT; - p = (u8 *)dmi + dmi->length; - while (s > 0) { - p += strlen(p); - p++; - s--; - } + break; + } - return p; + return 0; } -static void __init dmi_decode(DMIHeader *dmi) +/* + * Print the information for /proc/i8k. + */ +static int i8k_proc_show(struct seq_file *seq, void *offset) { - u8 *data = (u8 *) dmi; - char *p; - -#ifdef I8K_DEBUG - int i; - printk("%08x ", (int)data); - for (i=0; i<data[1] && i<64; i++) { - printk("%02x ", data[i]); - } - printk("\n"); -#endif - - switch (dmi->type) { - case 0: /* BIOS Information */ - p = dmi_string(dmi,data[5]); - if (*p) { - strlcpy(bios_version, p, sizeof(bios_version)); - string_trim(bios_version, sizeof(bios_version)); - } - break; - case 1: /* System Information */ - p = dmi_string(dmi,data[4]); - if (*p) { - strlcpy(system_vendor, p, sizeof(system_vendor)); - string_trim(system_vendor, sizeof(system_vendor)); - } - p = dmi_string(dmi,data[5]); - if (*p) { - strlcpy(product_name, p, sizeof(product_name)); - string_trim(product_name, sizeof(product_name)); - } - p = dmi_string(dmi,data[7]); - if (*p) { - strlcpy(serial_number, p, sizeof(serial_number)); - string_trim(serial_number, sizeof(serial_number)); - } - break; - } -} + int fn_key, cpu_temp, ac_power; + int left_fan, right_fan, left_speed, right_speed; + + cpu_temp = i8k_get_temp(0); /* 11100 µs */ + left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ + right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ + left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ + right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ + fn_key = i8k_get_fn_status(); /* 750 µs */ + if (power_status) + ac_power = i8k_get_power_status(); /* 14700 µs */ + else + ac_power = -1; -static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*)) -{ - u8 *buf; - u8 *data; - DMIHeader *dmi; - int i = 1; - - buf = ioremap(base, len); - if (buf == NULL) { - return -1; - } - data = buf; - - /* - * Stop when we see al the items the table claimed to have - * or we run off the end of the table (also happens) - */ - while ((i<num) && ((data-buf) < len)) { - dmi = (DMIHeader *)data; - /* - * Avoid misparsing crud if the length of the last - * record is crap - */ - if ((data-buf+dmi->length) >= len) { - break; - } - fn(dmi); - data += dmi->length; /* - * Don't go off the end of the data if there is - * stuff looking like string fill past the end + * Info: + * + * 1) Format version (this will change if format changes) + * 2) BIOS version + * 3) BIOS machine ID + * 4) Cpu temperature + * 5) Left fan status + * 6) Right fan status + * 7) Left fan speed + * 8) Right fan speed + * 9) AC power + * 10) Fn Key status */ - while (((data-buf) < len) && (*data || data[1])) { - data++; - } - data += 2; - i++; - } - iounmap(buf); - - return 0; + return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n", + I8K_PROC_FMT, + bios_version, + dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A", + cpu_temp, + left_fan, right_fan, left_speed, right_speed, + ac_power, fn_key); } -static int __init dmi_iterate(void (*decode)(DMIHeader *)) +static int i8k_open_fs(struct inode *inode, struct file *file) { - unsigned char buf[20]; - void __iomem *p = ioremap(0xe0000, 0x20000), *q; - - if (!p) - return -1; - - for (q = p; q < p + 0x20000; q += 16) { - memcpy_fromio(buf, q, 20); - if (memcmp(buf, "_DMI_", 5)==0) { - u16 num = buf[13]<<8 | buf[12]; - u16 len = buf [7]<<8 | buf [6]; - u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]; -#ifdef I8K_DEBUG - printk(KERN_INFO "DMI %d.%d present.\n", - buf[14]>>4, buf[14]&0x0F); - printk(KERN_INFO "%d structures occupying %d bytes.\n", - buf[13]<<8 | buf[12], - buf [7]<<8 | buf[6]); - printk(KERN_INFO "DMI table at 0x%08X.\n", - buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]); -#endif - if (dmi_table(base, len, num, decode)==0) { - iounmap(p); - return 0; - } - } - } - iounmap(p); - return -1; + return single_open(file, i8k_proc_show, NULL); } -/* end of DMI code */ - -/* - * Get DMI information. - */ -static int __init i8k_dmi_probe(void) -{ - char **p; - - if (dmi_iterate(dmi_decode) != 0) { - printk(KERN_INFO "i8k: unable to get DMI information\n"); - return -ENODEV; - } - - if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) { - printk(KERN_INFO "i8k: not running on a Dell system\n"); - return -ENODEV; - } - - for (p=supported_models; ; p++) { - if (!*p) { - printk(KERN_INFO "i8k: unsupported model: %s\n", product_name); - return -ENODEV; - } - if (strncmp(product_name,*p,strlen(*p)) == 0) { - break; - } - } - return 0; -} +static struct dmi_system_id __initdata i8k_dmi_table[] = { + { + .ident = "Dell Inspiron", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), + }, + }, + { + .ident = "Dell Latitude", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), + }, + }, + { + .ident = "Dell Inspiron 2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), + }, + }, + { + .ident = "Dell Latitude 2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), + }, + }, + { } +}; /* * Probe for the presence of a supported laptop. */ static int __init i8k_probe(void) { - char buff[4]; - int version; - int smm_found = 0; - - /* - * Get DMI information - */ - if (i8k_dmi_probe() != 0) { - printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", - system_vendor, product_name, bios_version); - } - - /* - * Get SMM Dell signature - */ - if (i8k_get_dell_signature() != 0) { - printk(KERN_INFO "i8k: unable to get SMM Dell signature\n"); - } else { - smm_found = 1; - } - - /* - * Get SMM BIOS version. - */ - version = i8k_get_bios_version(); - if (version <= 0) { - printk(KERN_INFO "i8k: unable to get SMM BIOS version\n"); - } else { - smm_found = 1; - buff[0] = (version >> 16) & 0xff; - buff[1] = (version >> 8) & 0xff; - buff[2] = (version) & 0xff; - buff[3] = '\0'; + char buff[4]; + int version; + /* - * If DMI BIOS version is unknown use SMM BIOS version. + * Get DMI information */ - if (bios_version[0] == '?') { - strcpy(bios_version, buff); + if (!dmi_check_system(i8k_dmi_table)) { + if (!ignore_dmi && !force) + return -ENODEV; + + printk(KERN_INFO "i8k: not running on a supported Dell system.\n"); + printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", + i8k_get_dmi_data(DMI_SYS_VENDOR), + i8k_get_dmi_data(DMI_PRODUCT_NAME), + i8k_get_dmi_data(DMI_BIOS_VERSION)); } + + strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version)); + /* - * Check if the two versions match. + * Get SMM Dell signature */ - if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) { - printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n", - buff, bios_version); + if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && + i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { + printk(KERN_ERR "i8k: unable to get SMM Dell signature\n"); + if (!force) + return -ENODEV; } - } - if (!smm_found && !force) { - return -ENODEV; - } + /* + * Get SMM BIOS version. + */ + version = i8k_get_bios_version(); + if (version <= 0) { + printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n"); + } else { + buff[0] = (version >> 16) & 0xff; + buff[1] = (version >> 8) & 0xff; + buff[2] = (version) & 0xff; + buff[3] = '\0'; + /* + * If DMI BIOS version is unknown use SMM BIOS version. + */ + if (!dmi_get_system_info(DMI_BIOS_VERSION)) + strlcpy(bios_version, buff, sizeof(bios_version)); + + /* + * Check if the two versions match. + */ + if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) + printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n", + buff, bios_version); + } - return 0; + return 0; } -#ifdef MODULE -static -#endif -int __init i8k_init(void) +static int __init i8k_init(void) { - struct proc_dir_entry *proc_i8k; - - /* Are we running on an supported laptop? */ - if (i8k_probe() != 0) { - return -ENODEV; - } - - /* Register the proc entry */ - proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info); - if (!proc_i8k) { - return -ENOENT; - } - proc_i8k->proc_fops = &i8k_fops; - proc_i8k->owner = THIS_MODULE; - - printk(KERN_INFO - "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", - I8K_VERSION); - - return 0; -} + struct proc_dir_entry *proc_i8k; -#ifdef MODULE -int init_module(void) -{ - return i8k_init(); + /* Are we running on an supported laptop? */ + if (i8k_probe()) + return -ENODEV; + + /* Register the proc entry */ + proc_i8k = create_proc_entry("i8k", 0, NULL); + if (!proc_i8k) + return -ENOENT; + + proc_i8k->proc_fops = &i8k_fops; + proc_i8k->owner = THIS_MODULE; + + printk(KERN_INFO + "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", + I8K_VERSION); + + return 0; } -void cleanup_module(void) +static void __exit i8k_exit(void) { - /* Remove the proc entry */ - remove_proc_entry("i8k", NULL); - - printk(KERN_INFO "i8k: module unloaded\n"); + remove_proc_entry("i8k", NULL); } -#endif -/* end of file */ +module_init(i8k_init); +module_exit(i8k_exit); diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c index fd299d6..cb8f419 100644 --- a/drivers/char/ip2/i2cmd.c +++ b/drivers/char/ip2/i2cmd.c @@ -97,7 +97,7 @@ static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME //static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING //static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB //static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB -static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS +//static UCHAR ct47[]={ 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS //static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB //static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB //static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB @@ -162,6 +162,7 @@ static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW // This routine sets the parameters of command 47 and returns a pointer to the // appropriate structure. //****************************************************************************** +#if 0 cmdSyntaxPtr i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) { @@ -175,6 +176,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) pCM->cmd[6] = (unsigned char) (lflag >> 8); return pCM; } +#endif /* 0 */ //****************************************************************************** // Function: i2cmdBaudDef(which, rate) @@ -187,7 +189,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) // This routine sets the parameters of commands 54 or 55 (according to the // argument which), and returns a pointer to the appropriate structure. //****************************************************************************** -cmdSyntaxPtr +static cmdSyntaxPtr i2cmdBaudDef(int which, unsigned short rate) { cmdSyntaxPtr pCM; diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h index c41728a..baa4e72 100644 --- a/drivers/char/ip2/i2cmd.h +++ b/drivers/char/ip2/i2cmd.h @@ -64,16 +64,6 @@ typedef struct _cmdSyntax // directly from user-level #define VAR 0x10 // This command is of variable length! -//----------------------------------- -// External declarations for i2cmd.c -//----------------------------------- -// Routine to set up parameters for the "define hot-key sequence" command. Since -// there is more than one parameter to assign, we must use a function rather -// than a macro (used usually). -// -extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag); -extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate); - // Declarations for the global arrays used to bear the commands and their // arguments. // @@ -433,6 +423,7 @@ static UCHAR cc02[]; #define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking #define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking +#if 0 // COMMAND 47: Send Protocol info via Unix flags: // iflag = Unix tty t_iflag // cflag = Unix tty t_cflag @@ -441,6 +432,7 @@ static UCHAR cc02[]; // within these flags // #define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag) +#endif /* 0 */ #define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl #define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 3b8314b..cf0cd58 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -2691,16 +2691,6 @@ no_xon: pCh->flags |= ASYNC_CHECK_CD; } -#ifdef XXX -do_flags_thing: // This is a test, we don't do the flags thing - - if ( (cflag & CRTSCTS) ) { - cflag |= 014000000000; - } - i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, - CMD_UNIX_FLAGS(iflag,cflag,lflag)); -#endif - service_it: i2DrainOutput( pCh, 100 ); } diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 601c7fc..1bbf507 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1756,7 +1756,7 @@ static void isicom_flush_buffer(struct tty_struct * tty) } -static int __init register_ioregion(void) +static int __devinit register_ioregion(void) { int count, done=0; for (count=0; count < BOARD_COUNT; count++ ) { @@ -1771,7 +1771,7 @@ static int __init register_ioregion(void) return done; } -static void __exit unregister_ioregion(void) +static void unregister_ioregion(void) { int count; for (count=0; count < BOARD_COUNT; count++ ) @@ -1803,7 +1803,7 @@ static struct tty_operations isicom_ops = { .tiocmset = isicom_tiocmset, }; -static int __init register_drivers(void) +static int __devinit register_drivers(void) { int error; @@ -1834,7 +1834,7 @@ static int __init register_drivers(void) return 0; } -static void __exit unregister_drivers(void) +static void unregister_drivers(void) { int error = tty_unregister_driver(isicom_normal); if (error) @@ -1842,7 +1842,7 @@ static void __exit unregister_drivers(void) put_tty_driver(isicom_normal); } -static int __init register_isr(void) +static int __devinit register_isr(void) { int count, done=0; unsigned long irqflags; @@ -1883,7 +1883,7 @@ static void __exit unregister_isr(void) } } -static int __init isicom_init(void) +static int __devinit isicom_init(void) { int card, channel, base; struct isi_port * port; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index c02a21d..52a073e 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -407,7 +407,6 @@ static unsigned long stli_eisamemprobeaddrs[] = { }; static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long); -int stli_eisaprobe = STLI_EISAPROBE; /* * Define the Stallion PCI vendor and device IDs. @@ -4685,7 +4684,7 @@ static int stli_initbrds(void) #ifdef MODULE stli_argbrds(); #endif - if (stli_eisaprobe) + if (STLI_EISAPROBE) stli_findeisabrds(); #ifdef CONFIG_PCI stli_findpcibrds(); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e3085b2..4218738 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -23,7 +23,10 @@ #include <linux/devfs_fs_kernel.h> #include <linux/ptrace.h> #include <linux/device.h> +#include <linux/highmem.h> +#include <linux/crash_dump.h> #include <linux/backing-dev.h> +#include <linux/bootmem.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -273,6 +276,40 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) return mmap_mem(file, vma); } +#ifdef CONFIG_CRASH_DUMP +/* + * Read memory corresponding to the old kernel. + */ +static ssize_t read_oldmem(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long pfn, offset; + size_t read = 0, csize; + int rc = 0; + + while (count) { + pfn = *ppos / PAGE_SIZE; + if (pfn > saved_max_pfn) + return read; + + offset = (unsigned long)(*ppos % PAGE_SIZE); + if (count > PAGE_SIZE - offset) + csize = PAGE_SIZE - offset; + else + csize = count; + + rc = copy_oldmem_page(pfn, buf, csize, offset, 1); + if (rc < 0) + return rc; + buf += csize; + *ppos += csize; + read += csize; + count -= csize; + } + return read; +} +#endif + extern long vread(char *buf, char *addr, unsigned long count); extern long vwrite(char *buf, char *addr, unsigned long count); @@ -721,6 +758,7 @@ static int open_port(struct inode * inode, struct file * filp) #define read_full read_zero #define open_mem open_port #define open_kmem open_mem +#define open_oldmem open_mem static struct file_operations mem_fops = { .llseek = memory_lseek, @@ -770,6 +808,13 @@ static struct file_operations full_fops = { .write = write_full, }; +#ifdef CONFIG_CRASH_DUMP +static struct file_operations oldmem_fops = { + .read = read_oldmem, + .open = open_oldmem, +}; +#endif + static ssize_t kmsg_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { @@ -825,6 +870,11 @@ static int memory_open(struct inode * inode, struct file * filp) case 11: filp->f_op = &kmsg_fops; break; +#ifdef CONFIG_CRASH_DUMP + case 12: + filp->f_op = &oldmem_fops; + break; +#endif default: return -ENXIO; } @@ -854,6 +904,9 @@ static const struct { {8, "random", S_IRUGO | S_IWUSR, &random_fops}, {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, +#ifdef CONFIG_CRASH_DUMP + {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, +#endif }; static struct class *mem_class; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 3115d31..31cf84d 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -66,8 +66,6 @@ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int pmu_device_init(void); -extern int tosh_init(void); -extern int i8k_init(void); #ifdef CONFIG_PROC_FS static void *misc_seq_start(struct seq_file *seq, loff_t *pos) @@ -314,12 +312,6 @@ static int __init misc_init(void) #ifdef CONFIG_PMAC_PBOOK pmu_device_init(); #endif -#ifdef CONFIG_TOSHIBA - tosh_init(); -#endif -#ifdef CONFIG_I8K - i8k_init(); -#endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index ab00f51..613aed9 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c @@ -107,8 +107,8 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, spin_unlock_irqrestore(&dsp_lock, flags); } -void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, - unsigned char ucValue) +static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, + unsigned char ucValue) { DSP_ISA_SLAVE_CONTROL rSlaveControl; DSP_ISA_SLAVE_CONTROL rSlaveControl_Save; @@ -141,6 +141,7 @@ void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, } +#if 0 unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, unsigned uIndex) { @@ -167,6 +168,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, return ucValue; } +#endif /* 0 */ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, unsigned short *pIrqMap, diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h index 3e7d020..270431c 100644 --- a/drivers/char/mwave/3780i.h +++ b/drivers/char/mwave/3780i.h @@ -338,10 +338,6 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO, unsigned long ulMsaAddr); void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, unsigned long ulMsaAddr, unsigned short usValue); -void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, - unsigned char ucValue); -unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, - unsigned uIndex); int dsp3780I_GetIPCSource(unsigned short usDspBaseIO, unsigned short *pusIPCSource); diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index ab650cd..d6c72e0 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -242,20 +242,14 @@ int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData) { int retval = 0; DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) struct resource *pres; -#endif PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); if ( pres == NULL ) retval = -EIO; -#else - retval = check_region(pSettings->usDspBaseIO, 16); - if (!retval) request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); -#endif + if (retval) { PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO); retval = -EIO; @@ -292,7 +286,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData) int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) { DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; - BOOLEAN bDSPPoweredUp = FALSE, bDSPEnabled = FALSE, bInterruptAllocated = FALSE; + BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE; PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData); @@ -397,8 +391,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) { PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n"); goto exit_cleanup; - } else { - bDSPEnabled = TRUE; } EnableSRAM(pBDData); @@ -411,8 +403,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) exit_cleanup: PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n"); - if (bDSPEnabled) - dsp3780I_DisableDSP(pSettings); if (bDSPPoweredUp) smapi_set_DSP_power_state(FALSE); if (bInterruptAllocated) { diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index f63a3fd..1af733d 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -211,12 +211,13 @@ nvram_check_checksum(void) return rv; } -void +static void __nvram_set_checksum(void) { mach_set_checksum(); } +#if 0 void nvram_set_checksum(void) { @@ -226,6 +227,7 @@ nvram_set_checksum(void) __nvram_set_checksum(); spin_unlock_irqrestore(&rtc_lock, flags); } +#endif /* 0 */ /* * The are the file operation function for user access to /dev/nvram @@ -921,6 +923,4 @@ EXPORT_SYMBOL(__nvram_write_byte); EXPORT_SYMBOL(nvram_write_byte); EXPORT_SYMBOL(__nvram_check_checksum); EXPORT_SYMBOL(nvram_check_checksum); -EXPORT_SYMBOL(__nvram_set_checksum); -EXPORT_SYMBOL(nvram_set_checksum); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h index e8f3860..01987c6 100644 --- a/drivers/char/rio/func.h +++ b/drivers/char/rio/func.h @@ -147,7 +147,6 @@ struct rio_info * rio_info_store( int cmd, struct rio_info * p); extern int rio_pcicopy(char *src, char *dst, int n); extern int rio_minor (struct tty_struct *tty); extern int rio_ismodem (struct tty_struct *tty); -extern void rio_udelay (int usecs); extern void rio_start_card_running (struct Host * HostP); diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 763893e..7db3370 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -354,11 +354,6 @@ int rio_ismodem(struct tty_struct *tty) } -void rio_udelay (int usecs) -{ - udelay (usecs); -} - static int rio_set_real_termios (void *ptr) { int rv, modem; diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index dca941e..898a126 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -37,6 +37,7 @@ static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3"; #include <linux/module.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/system.h> #include <asm/string.h> @@ -1560,14 +1561,14 @@ uint Slot; INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); WBYTE(DpRamP->DpResetTpu, 0xFF); - rio_udelay (3); + udelay(3); rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); WBYTE(DpRamP->DpResetTpu, 0xFF); - rio_udelay (3); + udelay(3); break; #ifdef FUTURE_RELEASE case RIO_EISA: @@ -1599,7 +1600,7 @@ uint Slot; DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; DpRamP->DpResetInt = 0xFF; DpRamP->DpResetTpu = 0xFF; - rio_udelay (100); + udelay(100); /* for (i=0; i<6000; i++); */ /* suspend( 3 ); */ break; diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index db65500..78a321a 100644 --- a/drivers/char/rio/riotty.c +++ b/drivers/char/rio/riotty.c @@ -524,16 +524,16 @@ riotclose(void *ptr) register uint SysPort = dev; struct ttystatics *tp; /* pointer to our ttystruct */ #endif - struct Port *PortP =ptr; /* pointer to the port structure */ + struct Port *PortP = ptr; /* pointer to the port structure */ int deleted = 0; int try = -1; /* Disable the timeouts by setting them to -1 */ int repeat_this = -1; /* Congrats to those having 15 years of uptime! (You get to break the driver.) */ - long end_time; + unsigned long end_time; struct tty_struct * tty; unsigned long flags; int Modem; - int rv =0; + int rv = 0; rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum); @@ -620,7 +620,7 @@ riotclose(void *ptr) if (repeat_this -- <= 0) { rv = -EINTR; rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); - RIOPreemptiveCmd(p, PortP, FCLOSE ); + RIOPreemptiveCmd(p, PortP, FCLOSE); goto close_end; } rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); @@ -656,14 +656,12 @@ riotclose(void *ptr) goto close_end; } - - /* Can't call RIOShortCommand with the port locked. */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) { - RIOPreemptiveCmd(p, PortP,FCLOSE); - goto close_end; + RIOPreemptiveCmd(p, PortP, FCLOSE); + goto close_end; } if (!deleted) @@ -698,7 +696,6 @@ riotclose(void *ptr) */ PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW); - #ifdef STATS PortP->Stat.CloseCnt++; #endif diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 5bcbeb0..f463d6b 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -161,6 +161,64 @@ static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { UPCI_AIOP_INTR_BIT_3 }; +static Byte_t RData[RDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, + 0x02, 0x09, 0x86, 0xfb, + 0x04, 0x09, 0x00, 0x0a, + 0x06, 0x09, 0x01, 0x0a, + 0x08, 0x09, 0x8a, 0x13, + 0x0a, 0x09, 0xc5, 0x11, + 0x0c, 0x09, 0x86, 0x85, + 0x0e, 0x09, 0x20, 0x0a, + 0x10, 0x09, 0x21, 0x0a, + 0x12, 0x09, 0x41, 0xff, + 0x14, 0x09, 0x82, 0x00, + 0x16, 0x09, 0x82, 0x7b, + 0x18, 0x09, 0x8a, 0x7d, + 0x1a, 0x09, 0x88, 0x81, + 0x1c, 0x09, 0x86, 0x7a, + 0x1e, 0x09, 0x84, 0x81, + 0x20, 0x09, 0x82, 0x7c, + 0x22, 0x09, 0x0a, 0x0a +}; + +static Byte_t RRegData[RREGDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ + 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ + 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ + 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ + 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ + 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ + 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ + 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ + 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ + 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ + 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ + 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ + 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ +}; + +static CONTROLLER_T sController[CTL_SIZE] = { + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} +}; + +static Byte_t sBitMapClrTbl[8] = { + 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f +}; + +static Byte_t sBitMapSetTbl[8] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 +}; + +static int sClockPrescale = 0x14; + /* * Line number is the ttySIx number (x), the Minor number. We * assign them sequentially, starting at zero. The following @@ -177,6 +235,26 @@ static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); static unsigned char GetLineNumber(int ctrl, int aiop, int ch); static unsigned char SetLineNumber(int ctrl, int aiop, int ch); static void rp_start(struct tty_struct *tty); +static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, + int ChanNum); +static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); +static void sFlushRxFIFO(CHANNEL_T * ChP); +static void sFlushTxFIFO(CHANNEL_T * ChP); +static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); +static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); +static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); +static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); +static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); +static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd); +static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, int AiopIOListSize, + int IRQNum, Byte_t Frequency, int PeriodicOnly); +static int sReadAiopID(ByteIO_t io); +static int sReadAiopNumChan(WordIO_t io); #ifdef MODULE MODULE_AUTHOR("Theodore Ts'o"); @@ -1798,7 +1876,7 @@ static void rp_flush_buffer(struct tty_struct *tty) * init's aiopic and serial port hardware. * Inputs: i is the board number (0-n) */ -__init int register_PCI(int i, struct pci_dev *dev) +static __init int register_PCI(int i, struct pci_dev *dev) { int num_aiops, aiop, max_num_aiops, num_chan, chan; unsigned int aiopio[MAX_AIOPS_PER_BOARD]; @@ -2453,72 +2531,6 @@ static void rp_cleanup_module(void) } #endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -static Byte_t RData[RDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ -}; - -CONTROLLER_T sController[CTL_SIZE] = { - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} -}; - -Byte_t sBitMapClrTbl[8] = { - 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f -}; - -Byte_t sBitMapSetTbl[8] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 -}; - -int sClockPrescale = 0x14; - /*************************************************************************** Function: sInitController Purpose: Initialization of controller global registers and controller @@ -2554,22 +2566,22 @@ Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, FREQ_4HZ - 4 Hertz If IRQNum is set to 0 the Frequency parameter is overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: TRUE if all interrupts except the periodic + int PeriodicOnly: 1 if all interrupts except the periodic interrupt are to be blocked. - FALSE is both the periodic interrupt and + 0 is both the periodic interrupt and other channel interrupts are allowed. If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of FALSE. + overidden, it is forced to a value of 0. Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller initialization failed. Comments: If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. + are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. If interrupts are to be completely disabled set IRQNum to 0. - Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an + Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an invalid combination. This function performs initialization of global interrupt modes, @@ -2589,9 +2601,9 @@ Warnings: No range checking on any of the parameters is done. After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum, - Byte_t Frequency, int PeriodicOnly) +static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, int AiopIOListSize, + int IRQNum, Byte_t Frequency, int PeriodicOnly) { int i; ByteIO_t io; @@ -2687,22 +2699,22 @@ Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, FREQ_4HZ - 4 Hertz If IRQNum is set to 0 the Frequency parameter is overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: TRUE if all interrupts except the periodic + int PeriodicOnly: 1 if all interrupts except the periodic interrupt are to be blocked. - FALSE is both the periodic interrupt and + 0 is both the periodic interrupt and other channel interrupts are allowed. If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of FALSE. + overidden, it is forced to a value of 0. Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller initialization failed. Comments: If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. + are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. If interrupts are to be completely disabled set IRQNum to 0. - Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an + Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an invalid combination. This function performs initialization of global interrupt modes, @@ -2722,11 +2734,11 @@ Warnings: No range checking on any of the parameters is done. After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, - ByteIO_t * AiopIOList, int AiopIOListSize, - WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, - int PeriodicOnly, int altChanRingIndicator, - int UPCIRingInd) +static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd) { int i; ByteIO_t io; @@ -2784,7 +2796,7 @@ Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X Warnings: No context switches are allowed while executing this function. */ -int sReadAiopID(ByteIO_t io) +static int sReadAiopID(ByteIO_t io) { Byte_t AiopID; /* ID byte from AIOP */ @@ -2810,7 +2822,7 @@ Comments: The number of channels is determined by write/reads from identical AIOP, otherwise it is an 8 channel. Warnings: No context switches are allowed while executing this function. */ -int sReadAiopNumChan(WordIO_t io) +static int sReadAiopNumChan(WordIO_t io) { Word_t x; static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; @@ -2834,15 +2846,15 @@ Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) CHANNEL_T *ChP; Ptr to channel structure int AiopNum; AIOP number within controller int ChanNum; Channel number within AIOP -Return: int: TRUE if initialization succeeded, FALSE if it fails because channel +Return: int: 1 if initialization succeeded, 0 if it fails because channel number exceeds number of channels available in AIOP. Comments: This function must be called before a channel can be used. Warnings: No range checking on any of the parameters is done. No context switches are allowed while executing this function. */ -int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, - int ChanNum) +static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, + int ChanNum) { int i; WordIO_t AiopIO; @@ -2853,7 +2865,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, int brd9600; if (ChanNum >= CtlP->AiopNumChan[AiopNum]) - return (FALSE); /* exceeds num chans in AIOP */ + return 0; /* exceeds num chans in AIOP */ /* Channel, AIOP, and controller identifiers */ ChP->CtlP = CtlP; @@ -2968,7 +2980,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, ChP->TxPrioBuf = ChOff + _TXP_BUF; sEnRxProcessor(ChP); /* start the Rx processor */ - return (TRUE); + return 1; } /*************************************************************************** @@ -2989,7 +3001,7 @@ Warnings: No context switches are allowed while executing this function. After calling this function a delay of 4 uS is required to ensure that the receive processor is no longer processing this channel. */ -void sStopRxProcessor(CHANNEL_T * ChP) +static void sStopRxProcessor(CHANNEL_T * ChP) { Byte_t R[4]; @@ -3014,18 +3026,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushRxFIFO(CHANNEL_T * ChP) +static void sFlushRxFIFO(CHANNEL_T * ChP) { int i; Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ + int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ return; /* don't need to flush */ - RxFIFOEnabled = FALSE; + RxFIFOEnabled = 0; if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ - RxFIFOEnabled = TRUE; + RxFIFOEnabled = 1; sDisRxFIFO(ChP); /* disable it */ for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ sInB(ChP->IntChan); /* depends on bus i/o timing */ @@ -3056,18 +3068,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushTxFIFO(CHANNEL_T * ChP) +static void sFlushTxFIFO(CHANNEL_T * ChP) { int i; Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* TRUE if transmitter enabled */ + int TxEnabled; /* 1 if transmitter enabled */ if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ return; /* don't need to flush */ - TxEnabled = FALSE; + TxEnabled = 0; if (ChP->TxControl[3] & TX_ENABLE) { - TxEnabled = TRUE; + TxEnabled = 1; sDisTransmit(ChP); /* disable transmitter */ } sStopRxProcessor(ChP); /* stop Rx processor */ @@ -3096,7 +3108,7 @@ Comments: The priority byte is transmitted before any data in the Tx FIFO. Warnings: No context switches are allowed while executing this function. */ -int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) +static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) { Byte_t DWBuf[4]; /* buffer for double word writes */ Word_t *WordPtr; /* must be far because Win SS != DS */ @@ -3158,7 +3170,7 @@ Comments: If an interrupt enable flag is set in Flags, that interrupt will be enable channel interrupts. This would allow the global interrupt status register to be used to determine which AIOPs need service. */ -void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) +static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) { Byte_t Mask; /* Interrupt Mask Register */ @@ -3202,7 +3214,7 @@ Comments: If an interrupt flag is set in Flags, that interrupt will be this channel's bit from being set in the AIOP's Interrupt Channel Register. */ -void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) +static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) { Byte_t Mask; /* Interrupt Mask Register */ @@ -3218,7 +3230,7 @@ void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) } } -void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) +static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) { sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); } @@ -3227,7 +3239,7 @@ void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) * Not an official SSCI function, but how to reset RocketModems. * ISA bus version */ -void sModemReset(CONTROLLER_T * CtlP, int chan, int on) +static void sModemReset(CONTROLLER_T * CtlP, int chan, int on) { ByteIO_t addr; Byte_t val; @@ -3252,7 +3264,7 @@ void sModemReset(CONTROLLER_T * CtlP, int chan, int on) * Not an official SSCI function, but how to reset RocketModems. * PCI bus version */ -void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) +static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) { ByteIO_t addr; diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 8026872..3a8bcc8 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -1130,46 +1130,6 @@ Warnings: This function writes the data byte without checking to see if */ #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) -int sInitController(CONTROLLER_T * CtlP, - int CtlNum, - ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, - int AiopIOListSize, - int IRQNum, Byte_t Frequency, int PeriodicOnly); - -int sPCIInitController(CONTROLLER_T * CtlP, - int CtlNum, - ByteIO_t * AiopIOList, - int AiopIOListSize, - WordIO_t ConfigIO, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly, - int altChanRingIndicator, int UPCIRingInd); - -int sReadAiopID(ByteIO_t io); -int sReadAiopNumChan(WordIO_t io); -int sInitChan(CONTROLLER_T * CtlP, - CHANNEL_T * ChP, int AiopNum, int ChanNum); -Byte_t sGetRxErrStatus(CHANNEL_T * ChP); -void sStopRxProcessor(CHANNEL_T * ChP); -void sStopSWInFlowCtl(CHANNEL_T * ChP); -void sFlushRxFIFO(CHANNEL_T * ChP); -void sFlushTxFIFO(CHANNEL_T * ChP); -int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); -void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); -void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); -void sModemReset(CONTROLLER_T * CtlP, int chan, int on); -void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); -void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); - -extern Byte_t R[RDATASIZE]; -extern CONTROLLER_T sController[CTL_SIZE]; -extern Byte_t sIRQMap[16]; -extern Byte_t sBitMapClrTbl[8]; -extern Byte_t sBitMapSetTbl[8]; -extern int sClockPrescale; - /* * Begin Linux specific definitions for the Rocketport driver * diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index f59f7cb..af79805 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/vt_kern.h> #include <linux/workqueue.h> +#include <linux/kexec.h> #include <asm/ptrace.h> @@ -94,6 +95,21 @@ static struct sysrq_key_op sysrq_unraw_op = { }; #endif /* CONFIG_VT */ +#ifdef CONFIG_KEXEC +/* crashdump sysrq handler */ +static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) +{ + crash_kexec(pt_regs); +} +static struct sysrq_key_op sysrq_crashdump_op = { + .handler = sysrq_handle_crashdump, + .help_msg = "Crashdump", + .action_msg = "Trigger a crashdump", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, struct tty_struct *tty) @@ -273,8 +289,12 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = { it is handled specially on the sparc and will never arrive */ /* b */ &sysrq_reboot_op, -/* c */ NULL, -/* d */ NULL, +#ifdef CONFIG_KEXEC +/* c */ &sysrq_crashdump_op, +#else +/* c */ NULL, +#endif +/* d */ NULL, /* e */ &sysrq_term_op, /* f */ &sysrq_moom_op, /* g */ NULL, diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 58e21fe..0c6f521 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -73,16 +73,20 @@ #define TOSH_MINOR_DEV 181 -static int tosh_id = 0x0000; -static int tosh_bios = 0x0000; -static int tosh_date = 0x0000; -static int tosh_sci = 0x0000; -static int tosh_fan = 0; - -static int tosh_fn = 0; +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); +MODULE_DESCRIPTION("Toshiba laptop SMM driver"); +MODULE_SUPPORTED_DEVICE("toshiba"); -module_param(tosh_fn, int, 0); +static int tosh_fn; +module_param_named(fn, tosh_fn, int, 0); +MODULE_PARM_DESC(fn, "User specified Fn key detection port"); +static int tosh_id; +static int tosh_bios; +static int tosh_date; +static int tosh_sci; +static int tosh_fan; static int tosh_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -359,7 +363,7 @@ static int tosh_get_machine_id(void) unsigned long address; id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa)); - + /* do we have a SCTTable machine identication number on our hands */ if (id==0xfc2f) { @@ -424,7 +428,7 @@ static int tosh_probe(void) } /* call the Toshiba SCI support check routine */ - + regs.eax = 0xf0f0; regs.ebx = 0x0000; regs.ecx = 0x0000; @@ -440,7 +444,7 @@ static int tosh_probe(void) /* if we get this far then we are running on a Toshiba (probably)! */ tosh_sci = regs.edx & 0xffff; - + /* next get the machine ID of the current laptop */ tosh_id = tosh_get_machine_id(); @@ -475,16 +479,15 @@ static int tosh_probe(void) return 0; } -int __init tosh_init(void) +static int __init toshiba_init(void) { int retval; /* are we running on a Toshiba laptop */ - if (tosh_probe()!=0) - return -EIO; + if (tosh_probe()) + return -ENODEV; - printk(KERN_INFO "Toshiba System Managment Mode driver v" - TOSH_VERSION"\n"); + printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n"); /* set the port to use for Fn status if not specified as a parameter */ if (tosh_fn==0x00) @@ -492,12 +495,12 @@ int __init tosh_init(void) /* register the device file */ retval = misc_register(&tosh_device); - if(retval < 0) + if (retval < 0) return retval; #ifdef CONFIG_PROC_FS /* register the proc entry */ - if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){ + if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) { misc_deregister(&tosh_device); return -ENOMEM; } @@ -506,27 +509,12 @@ int __init tosh_init(void) return 0; } -#ifdef MODULE -int init_module(void) -{ - return tosh_init(); -} - -void cleanup_module(void) +static void __exit toshiba_exit(void) { - /* remove the proc entry */ - remove_proc_entry("toshiba", NULL); - - /* unregister the device file */ - misc_deregister(&tosh_device); } -#endif -MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port"); -MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); -MODULE_DESCRIPTION("Toshiba laptop SMM driver"); -MODULE_SUPPORTED_DEVICE("toshiba"); +module_init(toshiba_init); +module_exit(toshiba_exit); diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5c843c9..854475c 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -233,10 +233,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, data[15], data[16], data[17], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], - be32_to_cpu(*((__be32 *) (data + 32)))); + be32_to_cpu(*((__be32 *) (data + 34)))); for (i = 0; i < 256; i++) { - str += sprintf(str, "%02X ", data[i + 39]); + str += sprintf(str, "%02X ", data[i + 38]); if ((i + 1) % 16 == 0) str += sprintf(str, "\n"); } @@ -464,6 +464,7 @@ void __devexit tpm_remove(struct pci_dev *pci_dev) pci_set_drvdata(pci_dev, NULL); misc_deregister(&chip->vendor->miscdev); + kfree(&chip->vendor->miscdev.name); sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group); @@ -526,7 +527,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); int tpm_register_hardware(struct pci_dev *pci_dev, struct tpm_vendor_specific *entry) { - char devname[7]; +#define DEVNAME_SIZE 7 + + char *devname; struct tpm_chip *chip; int i, j; @@ -569,7 +572,8 @@ dev_num_search_complete: else chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; - snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num); + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); + scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor->miscdev.name = devname; chip->vendor->miscdev.dev = &(pci_dev->dev); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 10cb450..373b41f 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -31,8 +31,8 @@ enum tpm_timeout { /* TPM addresses */ enum tpm_addr { + TPM_SUPERIO_ADDR = 0x2E, TPM_ADDR = 0x4E, - TPM_DATA = 0x4F }; extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, @@ -79,16 +79,16 @@ struct tpm_chip { struct list_head list; }; -static inline int tpm_read_index(int index) +static inline int tpm_read_index(int base, int index) { - outb(index, TPM_ADDR); - return inb(TPM_DATA) & 0xFF; + outb(index, base); + return inb(base+1) & 0xFF; } -static inline void tpm_write_index(int index, int value) +static inline void tpm_write_index(int base, int index, int value) { - outb(index, TPM_ADDR); - outb(value & 0xFF, TPM_DATA); + outb(index, base); + outb(value & 0xFF, base+1); } extern int tpm_register_hardware(struct pci_dev *, diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 61fe14a..cc2cc77 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -163,24 +163,24 @@ static int __devinit tpm_atml_init(struct pci_dev *pci_dev, if (pci_enable_device(pci_dev)) return -EIO; - lo = tpm_read_index( TPM_ATMEL_BASE_ADDR_LO ); - hi = tpm_read_index( TPM_ATMEL_BASE_ADDR_HI ); + lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); + hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); tpm_atmel.base = (hi<<8)|lo; dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); /* verify that it is an Atmel part */ - if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T' - || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') { + if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' + || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { rc = -ENODEV; goto out_err; } /* query chip for its version number */ - if ((version[0] = tpm_read_index(0x00)) != 0xFF) { - version[1] = tpm_read_index(0x01); - version[2] = tpm_read_index(0x02); - version[3] = tpm_read_index(0x03); + if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { + version[1] = tpm_read_index(TPM_ADDR, 0x01); + version[2] = tpm_read_index(TPM_ADDR, 0x02); + version[3] = tpm_read_index(TPM_ADDR, 0x03); } else { dev_info(&pci_dev->dev, "version query failed\n"); rc = -ENODEV; diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 1a45e7d..b412734 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -23,7 +23,6 @@ /* National definitions */ enum tpm_nsc_addr{ - TPM_NSC_BASE = 0x360, TPM_NSC_IRQ = 0x07, TPM_NSC_BASE0_HI = 0x60, TPM_NSC_BASE0_LO = 0x61, @@ -56,6 +55,7 @@ enum tpm_nsc_status { NSC_STATUS_RDY = 0x10, /* ready to receive command */ NSC_STATUS_IBR = 0x20 /* ready to receive data */ }; + /* command bits */ enum tpm_nsc_cmd_mode { NSC_COMMAND_NORMAL = 0x01, /* normal mode */ @@ -150,7 +150,8 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) *p = inb(chip->vendor->base + NSC_DATA); } - if ((data & NSC_STATUS_F0) == 0) { + if ((data & NSC_STATUS_F0) == 0 && + (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { dev_err(&chip->pci_dev->dev, "F0 not set\n"); return -EIO; } @@ -259,85 +260,64 @@ static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, { int rc = 0; int lo, hi; + int nscAddrBase = TPM_ADDR; - hi = tpm_read_index(TPM_NSC_BASE0_HI); - lo = tpm_read_index(TPM_NSC_BASE0_LO); - - tpm_nsc.base = (hi<<8) | lo; if (pci_enable_device(pci_dev)) return -EIO; + /* select PM channel 1 */ + tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12); + /* verify that it is a National part (SID) */ - if (tpm_read_index(NSC_SID_INDEX) != 0xEF) { - rc = -ENODEV; - goto out_err; + if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { + nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)| + (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE); + if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) { + rc = -ENODEV; + goto out_err; + } } + hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); + lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); + tpm_nsc.base = (hi<<8) | lo; + dev_dbg(&pci_dev->dev, "NSC TPM detected\n"); dev_dbg(&pci_dev->dev, "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", - tpm_read_index(0x07), tpm_read_index(0x20), - tpm_read_index(0x27)); + tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20), + tpm_read_index(nscAddrBase,0x27)); dev_dbg(&pci_dev->dev, "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n", - tpm_read_index(0x21), tpm_read_index(0x25), - tpm_read_index(0x26), tpm_read_index(0x28)); + tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25), + tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28)); dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n", - (tpm_read_index(0x60) << 8) | tpm_read_index(0x61)); + (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61)); dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n", - (tpm_read_index(0x62) << 8) | tpm_read_index(0x63)); + (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63)); dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n", - tpm_read_index(0x70)); + tpm_read_index(nscAddrBase,0x70)); dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n", - tpm_read_index(0x71)); + tpm_read_index(nscAddrBase,0x71)); dev_dbg(&pci_dev->dev, "NSC DMA channel select0 0x%x, select1 0x%x\n", - tpm_read_index(0x74), tpm_read_index(0x75)); + tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75)); dev_dbg(&pci_dev->dev, "NSC Config " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - tpm_read_index(0xF0), tpm_read_index(0xF1), - tpm_read_index(0xF2), tpm_read_index(0xF3), - tpm_read_index(0xF4), tpm_read_index(0xF5), - tpm_read_index(0xF6), tpm_read_index(0xF7), - tpm_read_index(0xF8), tpm_read_index(0xF9)); + tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1), + tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3), + tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5), + tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7), + tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9)); dev_info(&pci_dev->dev, - "NSC PC21100 TPM revision %d\n", - tpm_read_index(0x27) & 0x1F); - - if (tpm_read_index(NSC_LDC_INDEX) == 0) - dev_info(&pci_dev->dev, ": NSC TPM not active\n"); - - /* select PM channel 1 */ - tpm_write_index(NSC_LDN_INDEX, 0x12); - tpm_read_index(NSC_LDN_INDEX); - - /* disable the DPM module */ - tpm_write_index(NSC_LDC_INDEX, 0); - tpm_read_index(NSC_LDC_INDEX); - - /* set the data register base addresses */ - tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8); - tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE); - tpm_read_index(NSC_DIO_INDEX); - tpm_read_index(NSC_DIO_INDEX + 1); - - /* set the command register base addresses */ - tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8); - tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1)); - tpm_read_index(NSC_DIO_INDEX); - tpm_read_index(NSC_DIO_INDEX + 1); - - /* set the interrupt number to be used for the host interface */ - tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ); - tpm_write_index(NSC_ITS_INDEX, 0x00); - tpm_read_index(NSC_IRQ_INDEX); + "NSC TPM revision %d\n", + tpm_read_index(nscAddrBase, 0x27) & 0x1F); /* enable the DPM module */ - tpm_write_index(NSC_LDC_INDEX, 0x01); - tpm_read_index(NSC_LDC_INDEX); + tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0) goto out_err; @@ -355,6 +335,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, {0,} }; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index cc4b43b..6e4be3b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -94,6 +94,7 @@ #include <linux/idr.h> #include <linux/wait.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -2180,12 +2181,11 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) return tty_set_ldisc(tty, ldisc); } -static int send_break(struct tty_struct *tty, int duration) +static int send_break(struct tty_struct *tty, unsigned int duration) { tty->driver->break_ctl(tty, -1); if (!signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(duration); + msleep_interruptible(duration); } tty->driver->break_ctl(tty, 0); if (signal_pending(current)) @@ -2366,10 +2366,10 @@ int tty_ioctl(struct inode * inode, struct file * file, * all by anyone? */ if (!arg) - return send_break(tty, HZ/4); + return send_break(tty, 250); return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*(HZ/10) : HZ/4); + return send_break(tty, arg ? arg*100 : 250); case TIOCMGET: return tty_tiocmget(tty, file, p); diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index a3451cb..33b17c6 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -618,8 +618,8 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL); if (!short_name || !new_efivar) { - if (short_name) kfree(short_name); - if (new_efivar) kfree(new_efivar); + kfree(short_name); + kfree(new_efivar); return 1; } memset(short_name, 0, short_name_size+1); @@ -644,7 +644,8 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, kobj_set_kset_s(new_efivar, vars_subsys); kobject_register(&new_efivar->kobj); - kfree(short_name); short_name = NULL; + kfree(short_name); + short_name = NULL; spin_lock(&efivars_lock); list_add(&new_efivar->list, &efivar_list); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index d41ca31..03c23ce 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -20,13 +20,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <asm/io.h> -#ifdef CONFIG_FSL_OCP -#include <asm/ocp.h> -#define FSL_I2C_DEV_SEPARATE_DFSRR FS_I2C_SEPARATE_DFSRR -#define FSL_I2C_DEV_CLOCK_5200 FS_I2C_CLOCK_5200 -#else #include <linux/fsl_devices.h> -#endif #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/delay.h> @@ -294,204 +288,6 @@ static struct i2c_adapter mpc_ops = { .retries = 1 }; -#ifdef CONFIG_FSL_OCP -static int __devinit mpc_i2c_probe(struct ocp_device *ocp) -{ - int result = 0; - struct mpc_i2c *i2c; - - if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) { - return -ENOMEM; - } - memset(i2c, 0, sizeof(*i2c)); - - i2c->irq = ocp->def->irq; - i2c->flags = ((struct ocp_fs_i2c_data *)ocp->def->additions)->flags; - init_waitqueue_head(&i2c->queue); - - if (!request_mem_region(ocp->def->paddr, MPC_I2C_REGION, "i2c-mpc")) { - printk(KERN_ERR "i2c-mpc - resource unavailable\n"); - return -ENODEV; - } - - i2c->base = ioremap(ocp->def->paddr, MPC_I2C_REGION); - - if (!i2c->base) { - printk(KERN_ERR "i2c-mpc - failed to map controller\n"); - result = -ENOMEM; - goto fail_map; - } - - if (i2c->irq != OCP_IRQ_NA) - { - if ((result = request_irq(ocp->def->irq, mpc_i2c_isr, - SA_SHIRQ, "i2c-mpc", i2c)) < 0) { - printk(KERN_ERR - "i2c-mpc - failed to attach interrupt\n"); - goto fail_irq; - } - } else - i2c->irq = 0; - - mpc_i2c_setclock(i2c); - ocp_set_drvdata(ocp, i2c); - - i2c->adap = mpc_ops; - i2c_set_adapdata(&i2c->adap, i2c); - - if ((result = i2c_add_adapter(&i2c->adap)) < 0) { - printk(KERN_ERR "i2c-mpc - failed to add adapter\n"); - goto fail_add; - } - - return result; - - fail_add: - if (ocp->def->irq != OCP_IRQ_NA) - free_irq(ocp->def->irq, 0); - fail_irq: - iounmap(i2c->base); - fail_map: - release_mem_region(ocp->def->paddr, MPC_I2C_REGION); - kfree(i2c); - return result; -} -static void __devexit mpc_i2c_remove(struct ocp_device *ocp) -{ - struct mpc_i2c *i2c = ocp_get_drvdata(ocp); - i2c_del_adapter(&i2c->adap); - ocp_set_drvdata(ocp, NULL); - - if (ocp->def->irq != OCP_IRQ_NA) - free_irq(i2c->irq, i2c); - iounmap(i2c->base); - release_mem_region(ocp->def->paddr, MPC_I2C_REGION); - kfree(i2c); -} - -static struct ocp_device_id mpc_iic_ids[] __devinitdata = { - {.vendor = OCP_VENDOR_FREESCALE,.function = OCP_FUNC_IIC}, - {.vendor = OCP_VENDOR_INVALID} -}; - -MODULE_DEVICE_TABLE(ocp, mpc_iic_ids); - -static struct ocp_driver mpc_iic_driver = { - .name = "iic", - .id_table = mpc_iic_ids, - .probe = mpc_i2c_probe, - .remove = __devexit_p(mpc_i2c_remove) -}; - -static int __init iic_init(void) -{ - return ocp_register_driver(&mpc_iic_driver); -} - -static void __exit iic_exit(void) -{ - ocp_unregister_driver(&mpc_iic_driver); -} - -module_init(iic_init); -module_exit(iic_exit); -#else -static int fsl_i2c_probe(struct device *device) -{ - int result = 0; - struct mpc_i2c *i2c; - struct platform_device *pdev = to_platform_device(device); - struct fsl_i2c_platform_data *pdata; - struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data; - - if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) { - return -ENOMEM; - } - memset(i2c, 0, sizeof(*i2c)); - - i2c->irq = platform_get_irq(pdev, 0); - i2c->flags = pdata->device_flags; - init_waitqueue_head(&i2c->queue); - - i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION); - - if (!i2c->base) { - printk(KERN_ERR "i2c-mpc - failed to map controller\n"); - result = -ENOMEM; - goto fail_map; - } - - if (i2c->irq != 0) - if ((result = request_irq(i2c->irq, mpc_i2c_isr, - SA_SHIRQ, "i2c-mpc", i2c)) < 0) { - printk(KERN_ERR - "i2c-mpc - failed to attach interrupt\n"); - goto fail_irq; - } - - mpc_i2c_setclock(i2c); - dev_set_drvdata(device, i2c); - - i2c->adap = mpc_ops; - i2c_set_adapdata(&i2c->adap, i2c); - i2c->adap.dev.parent = &pdev->dev; - if ((result = i2c_add_adapter(&i2c->adap)) < 0) { - printk(KERN_ERR "i2c-mpc - failed to add adapter\n"); - goto fail_add; - } - - return result; - - fail_add: - if (i2c->irq != 0) - free_irq(i2c->irq, NULL); - fail_irq: - iounmap(i2c->base); - fail_map: - kfree(i2c); - return result; -}; - -static int fsl_i2c_remove(struct device *device) -{ - struct mpc_i2c *i2c = dev_get_drvdata(device); - - i2c_del_adapter(&i2c->adap); - dev_set_drvdata(device, NULL); - - if (i2c->irq != 0) - free_irq(i2c->irq, i2c); - - iounmap(i2c->base); - kfree(i2c); - return 0; -}; - -/* Structure for a device driver */ -static struct device_driver fsl_i2c_driver = { - .name = "fsl-i2c", - .bus = &platform_bus_type, - .probe = fsl_i2c_probe, - .remove = fsl_i2c_remove, -}; - -static int __init fsl_i2c_init(void) -{ - return driver_register(&fsl_i2c_driver); -} - -static void __exit fsl_i2c_exit(void) -{ - driver_unregister(&fsl_i2c_driver); -} - -module_init(fsl_i2c_init); -module_exit(fsl_i2c_exit); - -#endif /* CONFIG_FSL_OCP */ - MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); MODULE_DESCRIPTION ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors"); diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 2d9a9b7..629070b 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -1041,10 +1041,8 @@ static int hpsbpkt_thread(void *__hi) while (1) { if (down_interruptible(&khpsbpkt_sig)) { - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) continue; - } printk("khpsbpkt: received unexpected signal?!\n" ); break; } diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 32abb6d..9a46c3b 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1510,7 +1510,7 @@ static int nodemgr_host_thread(void *__hi) if (down_interruptible(&hi->reset_sem) || down_interruptible(&nodemgr_serialize)) { - if (try_to_freeze(PF_FREEZE)) + if (try_to_freeze()) continue; printk("NodeMgr: received unexpected signal?!\n" ); break; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index e152d0f..c77a82e 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -439,7 +439,7 @@ static int gameport_thread(void *nothing) do { gameport_handle_events(); wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); printk(KERN_DEBUG "gameport: kgameportd exiting\n"); diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 5900de3..a9bf549 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -396,7 +396,7 @@ static void i8042_stop(struct serio *serio) struct i8042_port *port = serio->port_data; port->exists = 0; - synchronize_kernel(); + synchronize_sched(); port->serio = NULL; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index feab497..341824c 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -344,7 +344,7 @@ static int serio_thread(void *nothing) do { serio_handle_events(); wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); printk(KERN_DEBUG "serio: kseriod exiting\n"); diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c index 40395f5..afa4668 100644 --- a/drivers/isdn/act2000/capi.c +++ b/drivers/isdn/act2000/capi.c @@ -224,6 +224,7 @@ actcapi_manufacturer_req_net(act2000_card *card) /* * Switch V.42 on or off */ +#if 0 int actcapi_manufacturer_req_v42(act2000_card *card, ulong arg) { @@ -242,6 +243,7 @@ actcapi_manufacturer_req_v42(act2000_card *card, ulong arg) ACTCAPI_QUEUE_TX; return 0; } +#endif /* 0 */ /* * Set error-handler diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h index 04d2bcd..f6d5f53 100644 --- a/drivers/isdn/act2000/capi.h +++ b/drivers/isdn/act2000/capi.h @@ -350,7 +350,6 @@ actcapi_nextsmsg(act2000_card *card) extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *); extern int actcapi_listen_req(act2000_card *); extern int actcapi_manufacturer_req_net(act2000_card *); -extern int actcapi_manufacturer_req_v42(act2000_card *, ulong); extern int actcapi_manufacturer_req_errh(act2000_card *); extern int actcapi_manufacturer_req_msn(act2000_card *); extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int); diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 55bed00..91dd055 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -955,7 +955,7 @@ EXPORT_SYMBOL(b1dma_release_appl); EXPORT_SYMBOL(b1dma_send_message); EXPORT_SYMBOL(b1dmactl_read_proc); -int b1dma_init(void) +static int __init b1dma_init(void) { char *p; char rev[32]; @@ -972,7 +972,7 @@ int b1dma_init(void) return 0; } -void b1dma_exit(void) +static void __exit b1dma_exit(void) { } diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index fa6b93b..724aac2 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -885,7 +885,7 @@ static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) } -void c4_reset_ctr(struct capi_ctr *ctrl) +static void c4_reset_ctr(struct capi_ctr *ctrl) { avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; avmctrl_info *cinfo; @@ -933,7 +933,7 @@ static void c4_remove(struct pci_dev *pdev) /* ------------------------------------------------------------- */ -void c4_register_appl(struct capi_ctr *ctrl, +static void c4_register_appl(struct capi_ctr *ctrl, u16 appl, capi_register_params *rp) { @@ -978,7 +978,7 @@ void c4_register_appl(struct capi_ctr *ctrl, /* ------------------------------------------------------------- */ -void c4_release_appl(struct capi_ctr *ctrl, u16 appl) +static void c4_release_appl(struct capi_ctr *ctrl, u16 appl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c index cb9d9ce..3b701d9 100644 --- a/drivers/isdn/hardware/avm/t1isa.c +++ b/drivers/isdn/hardware/avm/t1isa.c @@ -328,7 +328,7 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) return 0; } -void t1isa_reset_ctr(struct capi_ctr *ctrl) +static void t1isa_reset_ctr(struct capi_ctr *ctrl) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index 8d6bb56..293e277 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -23,7 +23,7 @@ endif # Multipart objects. hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ - st5481_b.o st5481_hdlc.o + st5481_b.o hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ lmgr.o q931.o callc.o fsm.o diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index c4f861a..8ae08c4 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -97,7 +97,7 @@ static WORD initAMD[] = { }; -void /* macro wWordAMD */ +static void /* macro wWordAMD */ WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val) { wByteAMD(cs, 0x00, reg); @@ -105,7 +105,7 @@ WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val) wByteAMD(cs, 0x01, HIBYTE(val)); } -WORD /* macro rWordAMD */ +static WORD /* macro rWordAMD */ ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg) { WORD res; @@ -665,7 +665,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg) } } -void +static void setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs) { @@ -676,7 +676,7 @@ setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs) } -void +static void DC_Close_Amd7930(struct IsdnCardState *cs) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: DC_Close called"); diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index 7546e2e..a98c5e3 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -22,7 +22,7 @@ extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.14.2.4 $"; +static const char *Asuscom_revision = "$Revision: 1.14.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -239,7 +239,7 @@ Start_IPAC: return IRQ_HANDLED; } -void +static void release_io_asuscom(struct IsdnCardState *cs) { int bytecnt = 8; diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 6fcb2cf..625799a 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -172,7 +172,7 @@ struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) return(NULL); } -void +static void write_ctrl(struct BCState *bcs, int which) { if (bcs->cs->debug & L1_DEB_HSCX) @@ -193,7 +193,7 @@ write_ctrl(struct BCState *bcs, int which) { } } -void +static void modehdlc(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -451,7 +451,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) { } } -inline void +static inline void HDLC_irq_main(struct IsdnCardState *cs) { u_int stat; @@ -487,7 +487,7 @@ HDLC_irq_main(struct IsdnCardState *cs) } } -void +static void hdlc_l2l1(struct PStack *st, int pr, void *arg) { struct BCState *bcs = st->l1.bcs; @@ -547,7 +547,7 @@ hdlc_l2l1(struct PStack *st, int pr, void *arg) } } -void +static void close_hdlcstate(struct BCState *bcs) { modehdlc(bcs, 0, 0); @@ -570,7 +570,7 @@ close_hdlcstate(struct BCState *bcs) } } -int +static int open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) { if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { @@ -598,7 +598,7 @@ open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) return (0); } -int +static int setstack_hdlc(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; @@ -612,6 +612,7 @@ setstack_hdlc(struct PStack *st, struct BCState *bcs) return (0); } +#if 0 void __init clear_pending_hdlc_ints(struct IsdnCardState *cs) { @@ -641,8 +642,9 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs) debugl1(cs, "HDLC 2 VIN %x", val); } } +#endif /* 0 */ -void __init +static void __init inithdlc(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_hdlc; diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index f410f62..dcb308a 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -23,7 +23,7 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $"; +static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $"; static inline u_char @@ -167,7 +167,7 @@ bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs) } } -void +static void release_io_bkm(struct IsdnCardState *cs) { if (cs->hw.ax.base) { diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 94bb83c..5f21b82 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -27,7 +27,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $"; +static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $"; static const char *sct_quadro_subtypes[] = { @@ -193,7 +193,7 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_sct_quadro(struct IsdnCardState *cs) { release_region(cs->hw.ax.base & 0xffffffc0, 128); @@ -261,7 +261,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return (0); } -int __init +static int __init sct_alloc_io(u_int adr, u_int len) { if (!request_region(adr, len, "scitel")) { diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 04065ab..7c56c44 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -874,7 +874,7 @@ release_b_st(struct Channel *chanp) } } -struct Channel +static struct Channel *selectfreechannel(struct PStack *st, int bch) { struct IsdnCardState *cs = st->l1.hardware; @@ -1429,7 +1429,7 @@ capi_debug(struct Channel *chanp, capi_msg *cm) HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf); } -void +static void lli_got_fac_req(struct Channel *chanp, capi_msg *cm) { if ((cm->para[0] != 3) || (cm->para[1] != 0)) return; @@ -1454,7 +1454,7 @@ lli_got_fac_req(struct Channel *chanp, capi_msg *cm) { } } -void +static void lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) { if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) || (cs->typ == ISDN_CTYPE_ELSA_PCI)) { diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 1663ee6..c542e6f 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -332,7 +332,7 @@ struct IsdnCard cards[HISAX_MAX_CARDS] = { #define HISAX_IDSIZE (HISAX_MAX_CARDS*8) static char HiSaxID[HISAX_IDSIZE] = { 0, }; -char *HiSax_id = HiSaxID; +static char *HiSax_id = HiSaxID; #ifdef MODULE /* Variables for insmod */ static int type[HISAX_MAX_CARDS] = { 0, }; @@ -391,7 +391,7 @@ char *HiSax_getrev(const char *revision) return rev; } -void __init HiSaxVersion(void) +static void __init HiSaxVersion(void) { char tmp[64]; @@ -608,6 +608,7 @@ static inline struct IsdnCardState *hisax_findcard(int driverid) /* * Find card with given card number */ +#if 0 struct IsdnCardState *hisax_get_card(int cardnr) { if ((cardnr <= nrcards) && (cardnr > 0)) @@ -615,8 +616,9 @@ struct IsdnCardState *hisax_get_card(int cardnr) return cards[cardnr - 1].cs; return NULL; } +#endif /* 0 */ -int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) +static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) { int count, cnt; u_char __user *p = buf; @@ -768,7 +770,7 @@ int ll_run(struct IsdnCardState *cs, int addfeatures) return 0; } -void ll_stop(struct IsdnCardState *cs) +static void ll_stop(struct IsdnCardState *cs) { isdn_ctrl ic; @@ -1184,7 +1186,7 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow return ret; } -void HiSax_shiftcards(int idx) +static void HiSax_shiftcards(int idx) { int i; @@ -1192,7 +1194,7 @@ void HiSax_shiftcards(int idx) memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); } -int HiSax_inithardware(int *busy_flag) +static int HiSax_inithardware(int *busy_flag) { int foundcards = 0; int i = 0; diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 394d481..b62d6b3 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -28,7 +28,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.33.2.6 $"; +static const char *Diva_revision = "$Revision: 1.33.2.6 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -706,7 +706,7 @@ diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_diva(struct IsdnCardState *cs) { int bytecnt; diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 4d7a025..110e9fd 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -33,13 +33,13 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.32.2.4 $"; -const char *Elsa_Types[] = +static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; +static const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", "PCMCIA-IPAC" }; -const char *ITACVer[] = +static const char *ITACVer[] = {"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", "B1", "A1"}; @@ -425,7 +425,7 @@ Start_IPAC: return IRQ_HANDLED; } -void +static void release_io_elsa(struct IsdnCardState *cs) { int bytecnt = 8; diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index 689c833..898ec09 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -237,7 +237,7 @@ static void mshutdown(struct IsdnCardState *cs) #endif } -inline int +static inline int write_modem(struct BCState *bcs) { int ret=0; struct IsdnCardState *cs = bcs->cs; @@ -275,7 +275,7 @@ write_modem(struct BCState *bcs) { return(ret); } -inline void +static inline void modem_fill(struct BCState *bcs) { if (bcs->tx_skb) { @@ -422,7 +422,7 @@ extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs); extern void modehscx(struct BCState *bcs, int mode, int bc); extern void hscx_l2l1(struct PStack *st, int pr, void *arg); -void +static void close_elsastate(struct BCState *bcs) { modehscx(bcs, 0, bcs->channel); @@ -442,7 +442,7 @@ close_elsastate(struct BCState *bcs) } } -void +static void modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { int count, fp; u_char *msg = buf; @@ -472,7 +472,7 @@ modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { } } -void +static void modem_set_init(struct IsdnCardState *cs) { int timeout; @@ -521,7 +521,7 @@ modem_set_init(struct IsdnCardState *cs) { udelay(RCV_DELAY); } -void +static void modem_set_dial(struct IsdnCardState *cs, int outgoing) { int timeout; #define RCV_DELAY 20000 @@ -543,7 +543,7 @@ modem_set_dial(struct IsdnCardState *cs, int outgoing) { udelay(RCV_DELAY); } -void +static void modem_l2l1(struct PStack *st, int pr, void *arg) { struct BCState *bcs = st->l1.bcs; @@ -579,7 +579,7 @@ modem_l2l1(struct PStack *st, int pr, void *arg) } } -int +static int setstack_elsa(struct PStack *st, struct BCState *bcs) { @@ -614,7 +614,7 @@ setstack_elsa(struct PStack *st, struct BCState *bcs) return (0); } -void +static void init_modem(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_elsa; @@ -641,7 +641,7 @@ init_modem(struct IsdnCardState *cs) { modem_set_init(cs); } -void +static void release_modem(struct IsdnCardState *cs) { cs->hw.elsa.MFlag = 0; diff --git a/drivers/isdn/hisax/enternow.h b/drivers/isdn/hisax/enternow.h deleted file mode 100644 index ed2eec5..0000000 --- a/drivers/isdn/hisax/enternow.h +++ /dev/null @@ -1,51 +0,0 @@ -/* 2001/10/02 - * - * enternow.h Header-file included by - * enternow_pci.c - * - * Author Christoph Ersfeld <info@formula-n.de> - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - */ - - -/* ***************************************************************************************** * - * ****************************** datatypes and macros ************************************* * - * ***************************************************************************************** */ - -#define BYTE unsigned char -#define WORD unsigned int -#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256)) -#define LOBYTE(w) ((unsigned char)(w & 0x00ff)) -#define InByte(addr) inb(addr) -#define OutByte(addr,val) outb(val,addr) - - - -/* ***************************************************************************************** * - * *********************************** card-specific *************************************** * - * ***************************************************************************************** */ - -/* für PowerISDN PCI */ -#define TJ_AMD_IRQ 0x20 -#define TJ_LED1 0x40 -#define TJ_LED2 0x80 - - -/* Das Fenster zum AMD... - * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in - * den TigerJet i/o-Raum gemappt - * -> 0x01 des AMD bei hw.njet.base + 0C4 */ -#define TJ_AMD_PORT 0xC0 - - - -/* ***************************************************************************************** * - * *************************************** Prototypen ************************************** * - * ***************************************************************************************** */ - -BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset); -void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value); diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c index 1cc4d11..3341cf1 100644 --- a/drivers/isdn/hisax/enternow_pci.c +++ b/drivers/isdn/hisax/enternow_pci.c @@ -65,7 +65,6 @@ #include "isac.h" #include "isdnl1.h" #include "amd7930_fn.h" -#include "enternow.h" #include <linux/interrupt.h> #include <linux/ppp_defs.h> #include <linux/pci.h> @@ -74,58 +73,72 @@ -const char *enternow_pci_rev = "$Revision: 1.1.4.5 $"; +static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $"; + + +/* für PowerISDN PCI */ +#define TJ_AMD_IRQ 0x20 +#define TJ_LED1 0x40 +#define TJ_LED2 0x80 + + +/* Das Fenster zum AMD... + * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in + * den TigerJet i/o-Raum gemappt + * -> 0x01 des AMD bei hw.njet.base + 0C4 */ +#define TJ_AMD_PORT 0xC0 + /* *************************** I/O-Interface functions ************************************* */ /* cs->readisac, macro rByteAMD */ -BYTE -ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset) +static unsigned char +ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset) { /* direktes Register */ if(offset < 8) - return (InByte(cs->hw.njet.isac + 4*offset)); + return (inb(cs->hw.njet.isac + 4*offset)); /* indirektes Register */ else { - OutByte(cs->hw.njet.isac + 4*AMD_CR, offset); - return(InByte(cs->hw.njet.isac + 4*AMD_DR)); + outb(offset, cs->hw.njet.isac + 4*AMD_CR); + return(inb(cs->hw.njet.isac + 4*AMD_DR)); } } /* cs->writeisac, macro wByteAMD */ -void -WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value) +static void +WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value) { /* direktes Register */ if(offset < 8) - OutByte(cs->hw.njet.isac + 4*offset, value); + outb(value, cs->hw.njet.isac + 4*offset); /* indirektes Register */ else { - OutByte(cs->hw.njet.isac + 4*AMD_CR, offset); - OutByte(cs->hw.njet.isac + 4*AMD_DR, value); + outb(offset, cs->hw.njet.isac + 4*AMD_CR); + outb(value, cs->hw.njet.isac + 4*AMD_DR); } } -void -enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) { +static void +enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) { if (!val) - OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00); + outb(0x00, cs->hw.njet.base+NETJET_IRQMASK1); else - OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ); + outb(TJ_AMD_IRQ, cs->hw.njet.base+NETJET_IRQMASK1); } -static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off) +static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off) { return(5); } -static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value) +static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value) { } @@ -142,18 +155,18 @@ reset_enpci(struct IsdnCardState *cs) /* Reset on, (also for AMD) */ cs->hw.njet.ctrl_reg = 0x07; - OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); mdelay(20); /* Reset off */ cs->hw.njet.ctrl_reg = 0x30; - OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); /* 20ms delay */ mdelay(20); cs->hw.njet.auxd = 0; // LED-status cs->hw.njet.dmactrl = 0; - OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); - OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ); - OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off + outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL); + outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); + outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off } @@ -161,7 +174,7 @@ static int enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) { u_long flags; - BYTE *chan; + unsigned char *chan; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt); @@ -187,16 +200,16 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) case MDL_ASSIGN: /* TEI assigned, LED1 on */ cs->hw.njet.auxd = TJ_AMD_IRQ << 1; - OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); + outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); break; case MDL_REMOVE: /* TEI removed, LEDs off */ cs->hw.njet.auxd = 0; - OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00); + outb(0x00, cs->hw.njet.base + NETJET_AUXDATA); break; case MDL_BC_ASSIGN: /* activate B-channel */ - chan = (BYTE *)arg; + chan = (unsigned char *)arg; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan); @@ -204,11 +217,11 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN"); /* at least one b-channel in use, LED 2 on */ cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; - OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); + outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); break; case MDL_BC_RELEASE: /* deactivate B-channel */ - chan = (BYTE *)arg; + chan = (unsigned char *)arg; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan); @@ -217,7 +230,7 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) /* no b-channel active -> LED2 off */ if (!(cs->dc.amd7930.lmr1 & 3)) { cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); - OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd); + outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); } break; default: @@ -231,11 +244,11 @@ static irqreturn_t enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; - BYTE s0val, s1val, ir; + unsigned char s0val, s1val, ir; u_long flags; spin_lock_irqsave(&cs->lock, flags); - s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1); + s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1); /* AMD threw an interrupt */ if (!(s1val & TJ_AMD_IRQ)) { @@ -245,13 +258,13 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) s1val = 1; } else s1val = 0; - s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0); + s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0); if ((s0val | s1val)==0) { // shared IRQ spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; } if (s0val) - OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); + outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0); /* DMA-Interrupt: B-channel-stuff */ /* set bits in sval to indicate which page is free */ @@ -342,20 +355,20 @@ setup_enternow_pci(struct IsdnCard *card) /* Reset an */ cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff - OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); /* 20 ms Pause */ mdelay(20); cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */ - OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); + outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); mdelay(10); cs->hw.njet.auxd = 0x00; // war 0xc0 cs->hw.njet.dmactrl = 0; - OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ); - OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ); - OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); + outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL); + outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); + outb(cs->hw.njet.auxd, cs->hw.njet.auxa); break; } diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 24a05a4..352b45a 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -21,7 +21,7 @@ #include <linux/pci.h> extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.19.2.4 $"; +static const char *gazel_revision = "$Revision: 2.19.2.4 $"; #define R647 1 #define R685 2 @@ -317,7 +317,8 @@ gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } -void + +static void release_io_gazel(struct IsdnCardState *cs) { unsigned int i; diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index ba1d028..6e7e060 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1358,7 +1358,7 @@ chipreset(hfc4s8s_hw * hw) /********************************************/ /* disable/enable hardware in nt or te mode */ /********************************************/ -void +static void hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode) { u_long flags; diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index ebea3fe..7cf8779 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -345,7 +345,7 @@ hfc_send_data(struct BCState *bcs) debugl1(cs,"send_data %d blocked", bcs->channel); } -void +static void main_rec_2bds0(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; @@ -399,7 +399,7 @@ main_rec_2bds0(struct BCState *bcs) return; } -void +static void mode_2bs0(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -505,7 +505,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg) } } -void +static void close_2bs0(struct BCState *bcs) { mode_2bs0(bcs, 0, bcs->channel); @@ -534,7 +534,7 @@ open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) return (0); } -int +static int setstack_2b(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; @@ -1004,7 +1004,7 @@ HFCD_l1hw(struct PStack *st, int pr, void *arg) } } -void +static void setstack_hfcd(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = HFCD_l1hw; @@ -1015,7 +1015,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs) { } -unsigned int __init +static unsigned int __init *init_send_hfcd(int cnt) { int i, *send; diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index bb376f3..f978a5a 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -52,7 +52,7 @@ WaitNoBusy(struct IsdnCardState *cs) return (to); } -int +static int GetFreeFifoBytes(struct BCState *bcs) { int s; @@ -66,7 +66,7 @@ GetFreeFifoBytes(struct BCState *bcs) return (s); } -int +static int ReadZReg(struct BCState *bcs, u_char reg) { int val; @@ -394,7 +394,7 @@ main_irq_hfc(struct BCState *bcs) return; } -void +static void mode_hfc(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -507,7 +507,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg) } -void +static void close_hfcstate(struct BCState *bcs) { mode_hfc(bcs, 0, bcs->channel); @@ -537,7 +537,7 @@ open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) return (0); } -int +static int setstack_hfc(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; @@ -551,7 +551,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs) return (0); } -void __init +static void __init init_send(struct BCState *bcs) { int i; diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index c2db526..8337b0f 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -70,7 +70,7 @@ static const PCI_ENTRY id_list[] = /******************************************/ /* free hardware resources used by driver */ /******************************************/ -void +static void release_io_hfcpci(struct IsdnCardState *cs) { printk(KERN_INFO "HiSax: release hfcpci at %p\n", @@ -394,7 +394,7 @@ receive_dmsg(struct IsdnCardState *cs) /*******************************************************************************/ /* check for transparent receive data and read max one threshold size if avail */ /*******************************************************************************/ -int +static int hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata) { unsigned short *z1r, *z2r; @@ -446,7 +446,7 @@ hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata) /**********************************/ /* B-channel main receive routine */ /**********************************/ -void +static void main_rec_hfcpci(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; @@ -1244,7 +1244,7 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg) /***********************************************/ /* called during init setting l1 stack pointer */ /***********************************************/ -void +static void setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = HFCPCI_l1hw; @@ -1268,7 +1268,7 @@ hfcpci_send_data(struct BCState *bcs) /***************************************************************/ /* activate/deactivate hardware for selected channels and mode */ /***************************************************************/ -void +static void mode_hfcpci(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -1579,7 +1579,7 @@ hfcpci_bh(struct IsdnCardState *cs) /********************************/ /* called for card init message */ /********************************/ -void __init +static void __init inithfcpci(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_2b; diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h index 4df036ed..9ef2981 100644 --- a/drivers/isdn/hisax/hfc_pci.h +++ b/drivers/isdn/hisax/hfc_pci.h @@ -232,5 +232,4 @@ typedef union { #define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b)) extern void main_irq_hcpci(struct BCState *bcs); -extern void inithfcpci(struct IsdnCardState *cs); extern void releasehfcpci(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index a307fcb..f27c160 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -308,7 +308,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) /******************************************/ /* free hardware resources used by driver */ /******************************************/ -void +static void release_io_hfcsx(struct IsdnCardState *cs) { cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ @@ -472,7 +472,7 @@ receive_dmsg(struct IsdnCardState *cs) /**********************************/ /* B-channel main receive routine */ /**********************************/ -void +static void main_rec_hfcsx(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; @@ -1003,7 +1003,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg) /***********************************************/ /* called during init setting l1 stack pointer */ /***********************************************/ -void +static void setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = HFCSX_l1hw; @@ -1027,7 +1027,7 @@ hfcsx_send_data(struct BCState *bcs) /***************************************************************/ /* activate/deactivate hardware for selected channels and mode */ /***************************************************************/ -void +static void mode_hfcsx(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -1328,7 +1328,7 @@ hfcsx_bh(struct IsdnCardState *cs) /********************************/ /* called for card init message */ /********************************/ -void __devinit +static void __devinit inithfcsx(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcsx; diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h index 12f5415..6792f13 100644 --- a/drivers/isdn/hisax/hfc_sx.h +++ b/drivers/isdn/hisax/hfc_sx.h @@ -193,5 +193,4 @@ struct hfcsx_extra { }; extern void main_irq_hfcsx(struct BCState *bcs); -extern void inithfcsx(struct IsdnCardState *cs); extern void releasehfcsx(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index ffd74b8..e2c3af4 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -60,7 +60,7 @@ static const char *hfcusb_revision = #include "hisax_debug.h" static u_int debug; module_param(debug, uint, 0); -int hfc_debug; +static int hfc_debug; #endif @@ -85,7 +85,7 @@ static struct usb_device_id hfc_usb_idtab[] = { * VendorID, ProductID, Devicename, LED_SCHEME, * LED's BitMask in HFCUSB_P_DATA Register : LED_USB, LED_S0, LED_B1, LED_B2 */ -vendor_data vdata[] = { +static vendor_data vdata[] = { /* CologneChip Eval TA */ {0x0959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", LED_OFF, {4, 0, 2, 1} @@ -1137,7 +1137,7 @@ set_hfcmode(hfcusb_data * hfc, int channel, int mode) } } -void +static void hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg) { usb_fifo *fifo = my_hisax_if->priv; diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h index b171600..280dd29 100644 --- a/drivers/isdn/hisax/hfc_usb.h +++ b/drivers/isdn/hisax/hfc_usb.h @@ -168,7 +168,7 @@ static struct hfcusb_symbolic_list urb_errlist[] = { * 3 entries are the configuration number, the minimum interval for * Interrupt endpoints & boolean if E-channel logging possible */ -int validconf[][19] = { +static int validconf[][19] = { // INT in, ISO out config {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, @@ -187,7 +187,7 @@ int validconf[][19] = { }; // string description of chosen config -char *conf_str[] = { +static char *conf_str[] = { "4 Interrupt IN + 3 Isochron OUT", "3 Interrupt IN + 3 Isochron OUT", "4 Isochron IN + 3 Isochron OUT", diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c index 6fc55fe..86ab1c1 100644 --- a/drivers/isdn/hisax/hfcscard.c +++ b/drivers/isdn/hisax/hfcscard.c @@ -52,7 +52,7 @@ hfcs_Timer(struct IsdnCardState *cs) */ } -void +static void release_io_hfcs(struct IsdnCardState *cs) { release2bds0(cs); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index dc57917..17cf766 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1271,7 +1271,6 @@ extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, void init_bcstate(struct IsdnCardState *cs, int bc); void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs); -unsigned int random_ri(void); void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st); void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); @@ -1315,15 +1314,11 @@ int QuickHex(char *txt, u_char * p, int cnt); void LogFrame(struct IsdnCardState *cs, u_char * p, int size); void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); void iecpy(u_char * dest, u_char * iestart, int ieoffset); -#ifdef ISDN_CHIP_ISAC -void setstack_isac(struct PStack *st, struct IsdnCardState *cs); -#endif /* ISDN_CHIP_ISAC */ #endif /* __KERNEL__ */ #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} int ll_run(struct IsdnCardState *cs, int addfeatures); -void ll_stop(struct IsdnCardState *cs); int CallcNew(void); void CallcFree(void); int CallcNewChan(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c index 5bbbe3e..66dbaee 100644 --- a/drivers/isdn/hisax/hscx.c +++ b/drivers/isdn/hisax/hscx.c @@ -151,7 +151,7 @@ hscx_l2l1(struct PStack *st, int pr, void *arg) } } -void +static void close_hscxstate(struct BCState *bcs) { modehscx(bcs, 0, bcs->channel); @@ -203,7 +203,7 @@ open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs) return (0); } -int +static int setstack_hscx(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index dcf31f8..b4ca585 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -108,7 +108,7 @@ icc_bh(struct IsdnCardState *cs) #endif } -void +static void icc_empty_fifo(struct IsdnCardState *cs, int count) { u_char *ptr; @@ -563,13 +563,13 @@ ICC_l1hw(struct PStack *st, int pr, void *arg) } } -void +static void setstack_icc(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = ICC_l1hw; } -void +static void DC_Close_icc(struct IsdnCardState *cs) { if (cs->dc.icc.mon_rx) { kfree(cs->dc.icc.mon_rx); diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c index 6485e23..efba2f4 100644 --- a/drivers/isdn/hisax/ipacx.c +++ b/drivers/isdn/hisax/ipacx.c @@ -36,8 +36,6 @@ static void ph_command(struct IsdnCardState *cs, unsigned int command); static inline void cic_int(struct IsdnCardState *cs); static void dch_l2l1(struct PStack *st, int pr, void *arg); static void dbusy_timer_handler(struct IsdnCardState *cs); -static void ipacx_new_ph(struct IsdnCardState *cs); -static void dch_bh(struct IsdnCardState *cs); static void dch_empty_fifo(struct IsdnCardState *cs, int count); static void dch_fill_fifo(struct IsdnCardState *cs); static inline void dch_int(struct IsdnCardState *cs); @@ -232,81 +230,6 @@ dbusy_timer_handler(struct IsdnCardState *cs) } //---------------------------------------------------------- -// L1 state machine intermediate layer to isdnl1 module -//---------------------------------------------------------- -static void -ipacx_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.isac.ph_state) { - case (IPACX_IND_RES): - ph_command(cs, IPACX_CMD_DI); - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - - case (IPACX_IND_DC): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - - case (IPACX_IND_DR): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - - case (IPACX_IND_PU): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - - case (IPACX_IND_RSY): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - - case (IPACX_IND_AR): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - - case (IPACX_IND_AI8): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - - case (IPACX_IND_AI10): - l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); - break; - - default: - break; - } -} - -//---------------------------------------------------------- -// bottom half handler for D channel -//---------------------------------------------------------- -static void -dch_bh(struct IsdnCardState *cs) -{ - struct PStack *st; - - if (!cs) return; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) debugl1(cs, "D-Channel Busy cleared"); - for (st = cs->stlist; st; st = st->next) { - st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); - } - } - - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) { - DChannel_proc_rcv(cs); - } - - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) { - DChannel_proc_xmt(cs); - } - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - ipacx_new_ph(cs); - } -} - -//---------------------------------------------------------- // Fill buffer from receive FIFO //---------------------------------------------------------- static void @@ -991,14 +914,5 @@ init_ipacx(struct IsdnCardState *cs, int part) } } - -void __devinit -setup_ipacx(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs); - cs->dbusytimer.function = (void *) dbusy_timer_handler; - cs->dbusytimer.data = (long) cs; - init_timer(&cs->dbusytimer); -} //----------------- end of file ----------------------- diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 20b9499..85e063a 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -112,7 +112,7 @@ isac_bh(struct IsdnCardState *cs) #endif } -void +static void isac_empty_fifo(struct IsdnCardState *cs, int count) { u_char *ptr; @@ -563,13 +563,13 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg) } } -void +static void setstack_isac(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = ISAC_l1hw; } -void +static void DC_Close_isac(struct IsdnCardState *cs) { if (cs->dc.isac.mon_rx) { kfree(cs->dc.isac.mon_rx); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index ee081321..642a87c 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -21,13 +21,13 @@ #define ETX 0x03 #define FAXMODCNT 13 -const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; +static const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; static u_int modmask = 0x1fff; static int frm_extra_delay = 2; static int para_TOA = 6; -const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" }; +static const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" }; -void isar_setup(struct IsdnCardState *cs); +static void isar_setup(struct IsdnCardState *cs); static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para); static void ll_deliver_faxstat(struct BCState *bcs, u_char status); @@ -45,7 +45,7 @@ waitforHIA(struct IsdnCardState *cs, int timeout) } -int +static int sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, u_char *msg) { @@ -85,7 +85,7 @@ sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, } /* Call only with IRQ disabled !!! */ -inline void +static inline void rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg) { int i; @@ -114,7 +114,7 @@ rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg) } /* Call only with IRQ disabled !!! */ -inline void +static inline void get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg) { ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS); @@ -127,7 +127,7 @@ get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg) #endif } -int +static int waitrecmsg(struct IsdnCardState *cs, u_char *len, u_char *msg, int maxdelay) { @@ -185,7 +185,7 @@ ISARVersion(struct IsdnCardState *cs, char *s) return(ver); } -int +static int isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf) { int ret, size, cnt, debug; @@ -739,7 +739,7 @@ isar_fill_fifo(struct BCState *bcs) } } -inline +static inline struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath) { if ((!dpath) || (dpath == 3)) @@ -751,7 +751,7 @@ struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath) return(NULL); } -void +static void send_frames(struct BCState *bcs) { if (bcs->tx_skb) { @@ -806,7 +806,7 @@ send_frames(struct BCState *bcs) } } -inline void +static inline void check_send(struct IsdnCardState *cs, u_char rdm) { struct BCState *bcs; @@ -828,11 +828,13 @@ check_send(struct IsdnCardState *cs, u_char rdm) } -const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4", - "300", "600", "1200", "2400", "4800", "7200", - "9600nt", "9600t", "12000", "14400", "WRONG"}; -const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", - "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; +static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", + "NODEF4", "300", "600", "1200", "2400", + "4800", "7200", "9600nt", "9600t", "12000", + "14400", "WRONG"}; +static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", + "Bell103", "V23", "Bell202", "V17", "V29", + "V27ter"}; static void isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { @@ -1388,7 +1390,7 @@ setup_iom2(struct BCState *bcs) { udelay(1000); } -int +static int modeisar(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -1562,7 +1564,7 @@ isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); } -void +static void isar_setup(struct IsdnCardState *cs) { u_char msg; @@ -1582,7 +1584,7 @@ isar_setup(struct IsdnCardState *cs) } } -void +static void isar_l2l1(struct PStack *st, int pr, void *arg) { struct BCState *bcs = st->l1.bcs; @@ -1681,7 +1683,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg) } } -void +static void close_isarstate(struct BCState *bcs) { modeisar(bcs, 0, bcs->channel); @@ -1703,7 +1705,7 @@ close_isarstate(struct BCState *bcs) del_timer(&bcs->hw.isar.ftimer); } -int +static int open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) { if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { @@ -1725,7 +1727,7 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) return (0); } -int +static int setstack_isar(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 4d08d27..ac89950 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -151,7 +151,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...) va_end(args); } -void +static void L1activated(struct IsdnCardState *cs) { struct PStack *st; @@ -166,7 +166,7 @@ L1activated(struct IsdnCardState *cs) } } -void +static void L1deactivated(struct IsdnCardState *cs) { struct PStack *st; @@ -370,7 +370,7 @@ init_bcstate(struct IsdnCardState *cs, int bc) #ifdef L2FRAME_DEBUG /* psa */ -char * +static char * l2cmd(u_char cmd) { switch (cmd & ~0x10) { @@ -404,7 +404,7 @@ l2cmd(u_char cmd) static char tmpdeb[32]; -char * +static char * l2frames(u_char * ptr) { switch (ptr[2] & ~0x10) { diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index d311b5f..9022583 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -142,7 +142,7 @@ freewin1(struct Layer2 *l2) return cnt; } -inline void +static inline void freewin(struct PStack *st) { freewin1(&st->l2); @@ -157,7 +157,7 @@ ReleaseWin(struct Layer2 *l2) printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt); } -inline unsigned int +static inline unsigned int cansend(struct PStack *st) { unsigned int p1; @@ -169,7 +169,7 @@ cansend(struct PStack *st) return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag)); } -inline void +static inline void clear_exception(struct Layer2 *l2) { test_and_clear_bit(FLG_ACK_PEND, &l2->flag); @@ -178,7 +178,7 @@ clear_exception(struct Layer2 *l2) clear_peer_busy(l2); } -inline int +static inline int l2headersize(struct Layer2 *l2, int ui) { return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + @@ -223,40 +223,31 @@ enqueue_super(struct PStack *st, #define enqueue_ui(a, b) enqueue_super(a, b) -inline int +static inline int IsUI(u_char * data) { return ((data[0] & 0xef) == UI); } -inline int +static inline int IsUA(u_char * data) { return ((data[0] & 0xef) == UA); } -inline int +static inline int IsDM(u_char * data) { return ((data[0] & 0xef) == DM); } -inline int +static inline int IsDISC(u_char * data) { return ((data[0] & 0xef) == DISC); } -inline int -IsRR(u_char * data, struct PStack *st) -{ - if (test_bit(FLG_MOD128, &st->l2.flag)) - return (data[0] == RR); - else - return ((data[0] & 0xf) == 1); -} - -inline int +static inline int IsSFrame(u_char * data, struct PStack *st) { register u_char d = *data; @@ -266,7 +257,7 @@ IsSFrame(u_char * data, struct PStack *st) return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c)); } -inline int +static inline int IsSABME(u_char * data, struct PStack *st) { u_char d = data[0] & ~0x10; @@ -274,25 +265,25 @@ IsSABME(u_char * data, struct PStack *st) return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM); } -inline int +static inline int IsREJ(u_char * data, struct PStack *st) { return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ); } -inline int +static inline int IsFRMR(u_char * data) { return ((data[0] & 0xef) == FRMR); } -inline int +static inline int IsRNR(u_char * data, struct PStack *st) { return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR); } -int +static int iframe_error(struct PStack *st, struct sk_buff *skb) { int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); @@ -315,7 +306,7 @@ iframe_error(struct PStack *st, struct sk_buff *skb) return 0; } -int +static int super_error(struct PStack *st, struct sk_buff *skb) { if (skb->len != l2addrsize(&st->l2) + @@ -325,7 +316,7 @@ super_error(struct PStack *st, struct sk_buff *skb) return 0; } -int +static int unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp) { int rsp = (*skb->data & 0x2) >> 1; @@ -341,7 +332,7 @@ unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp) return 0; } -int +static int UI_error(struct PStack *st, struct sk_buff *skb) { int rsp = *skb->data & 0x2; @@ -357,7 +348,7 @@ UI_error(struct PStack *st, struct sk_buff *skb) return 0; } -int +static int FRMR_error(struct PStack *st, struct sk_buff *skb) { int headers = l2addrsize(&st->l2) + 1; @@ -444,51 +435,44 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr) enqueue_super(st, skb); } -inline u_char +static inline u_char get_PollFlag(struct PStack * st, struct sk_buff * skb) { return (skb->data[l2addrsize(&(st->l2))] & 0x10); } -inline void -FreeSkb(struct sk_buff *skb) -{ - dev_kfree_skb(skb); -} - - -inline u_char +static inline u_char get_PollFlagFree(struct PStack *st, struct sk_buff *skb) { u_char PF; PF = get_PollFlag(st, skb); - FreeSkb(skb); + dev_kfree_skb(skb); return (PF); } -inline void +static inline void start_t200(struct PStack *st, int i) { FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); test_and_set_bit(FLG_T200_RUN, &st->l2.flag); } -inline void +static inline void restart_t200(struct PStack *st, int i) { FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); test_and_set_bit(FLG_T200_RUN, &st->l2.flag); } -inline void +static inline void stop_t200(struct PStack *st, int i) { if(test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) FsmDelTimer(&st->l2.t200, i); } -inline void +static inline void st5_dl_release_l2l3(struct PStack *st) { int pr; @@ -501,7 +485,7 @@ st5_dl_release_l2l3(struct PStack *st) st->l2.l2l3(st, pr, NULL); } -inline void +static inline void lapb_dl_release_l2l3(struct PStack *st, int f) { if (test_bit(FLG_LAPB, &st->l2.flag)) @@ -802,7 +786,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg) l2_mdl_error_ua(fi, event, arg); return; } - FreeSkb(skb); + dev_kfree_skb(skb); if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) l2_disconnect(fi, event, arg); @@ -840,7 +824,7 @@ l2_released(struct FsmInst *fi, int event, void *arg) l2_mdl_error_ua(fi, event, arg); return; } - FreeSkb(skb); + dev_kfree_skb(skb); stop_t200(st, 6); lapb_dl_release_l2l3(st, CONFIRM); @@ -889,7 +873,7 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) } } -inline void +static inline void enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) { struct sk_buff *skb; @@ -912,7 +896,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) enqueue_super(st, skb); } -inline void +static inline void enquiry_response(struct PStack *st) { if (test_bit(FLG_OWN_BUSY, &st->l2.flag)) @@ -922,7 +906,7 @@ enquiry_response(struct PStack *st) test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); } -inline void +static inline void transmit_enquiry(struct PStack *st) { if (test_bit(FLG_OWN_BUSY, &st->l2.flag)) @@ -1004,7 +988,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg) PollFlag = (skb->data[0] & 0x10); nr = (skb->data[0] >> 5) & 0x7; } - FreeSkb(skb); + dev_kfree_skb(skb); if (PollFlag) { if (rsp) @@ -1047,7 +1031,7 @@ l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) if (!test_bit(FLG_L3_INIT, &st->l2.flag)) skb_queue_tail(&st->l2.i_queue, skb); else - FreeSkb(skb); + dev_kfree_skb(skb); } static void @@ -1093,7 +1077,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) nr = (skb->data[i] >> 5) & 0x7; } if (test_bit(FLG_OWN_BUSY, &l2->flag)) { - FreeSkb(skb); + dev_kfree_skb(skb); if(PollFlag) enquiry_response(st); } else if (l2->vr == ns) { (l2->vr)++; @@ -1111,7 +1095,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) st->l2.l2l3(st, DL_DATA | INDICATION, skb); } else { /* n(s)!=v(r) */ - FreeSkb(skb); + dev_kfree_skb(skb); if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { if (PollFlag) enquiry_response(st); @@ -1309,7 +1293,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) skb = alloc_skb(oskb->len + i, GFP_ATOMIC); memcpy(skb_put(skb, i), header, i); memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len); - FreeSkb(oskb); + dev_kfree_skb(oskb); } st->l2.l2l1(st, PH_PULL | INDICATION, skb); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); @@ -1349,7 +1333,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg) PollFlag = (skb->data[0] & 0x10); nr = (skb->data[0] >> 5) & 0x7; } - FreeSkb(skb); + dev_kfree_skb(skb); if (rsp && PollFlag) { if (legalnr(st, nr)) { @@ -1391,7 +1375,7 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg) establishlink(fi); test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); } - FreeSkb(skb); + dev_kfree_skb(skb); } static void @@ -1655,7 +1639,7 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg) datap += len; else { FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N'); - FreeSkb(skb); + dev_kfree_skb(skb); return; } if (!(*datap & 1)) { /* I-Frame */ @@ -1684,16 +1668,16 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg) ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); } else { FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L'); - FreeSkb(skb); + dev_kfree_skb(skb); ret = 0; } if(c) { - FreeSkb(skb); + dev_kfree_skb(skb); FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c); ret = 0; } if (ret) - FreeSkb(skb); + dev_kfree_skb(skb); break; case (PH_PULL | CONFIRM): FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index f571b5d..abcc953 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -390,7 +390,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp) } } -void +static void isdnl3_trans(struct PStack *st, int pr, void *arg) { st->l3.l3l2(st, pr, arg); } diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c index af5171d..33747af 100644 --- a/drivers/isdn/hisax/isurf.c +++ b/drivers/isdn/hisax/isurf.c @@ -122,7 +122,7 @@ isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_isurf(struct IsdnCardState *cs) { release_region(cs->hw.isurf.reset, 1); diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index b843b75..908a7e1 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -25,7 +25,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *ix1_revision = "$Revision: 2.12.2.4 $"; +static const char *ix1_revision = "$Revision: 2.12.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -162,7 +162,7 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_ix1micro(struct IsdnCardState *cs) { if (cs->hw.ix1.cfg_reg) diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index f05d527..363ae31 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -74,7 +74,7 @@ jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value) -void +static void modejade(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -190,7 +190,7 @@ jade_l2l1(struct PStack *st, int pr, void *arg) } } -void +static void close_jadestate(struct BCState *bcs) { modejade(bcs, 0, bcs->channel); @@ -243,7 +243,7 @@ open_jadestate(struct IsdnCardState *cs, struct BCState *bcs) } -int +static int setstack_jade(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h index fa29444..29055e1 100644 --- a/drivers/isdn/hisax/jade.h +++ b/drivers/isdn/hisax/jade.h @@ -128,7 +128,6 @@ #define jade_TXAUDIOCH2CFG 0x1A extern int JadeVersion(struct IsdnCardState *cs, char *s); -extern void modejade(struct BCState *bcs, int mode, int bc); extern void clear_pending_jade_ints(struct IsdnCardState *cs); extern void initjade(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c index d6c1c8f..c5c36ee 100644 --- a/drivers/isdn/hisax/l3_1tr6.c +++ b/drivers/isdn/hisax/l3_1tr6.c @@ -19,7 +19,7 @@ #include <linux/ctype.h> extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $"; +static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index ec92308..a6d2abd 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -26,7 +26,7 @@ #include <linux/config.h> extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.32.2.3 $"; +static const char *dss1_revision = "$Revision: 2.32.2.3 $"; #define EXT_BEARER_CAPS 1 diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index 3ab3a54..f7041d5 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -24,7 +24,7 @@ #include <linux/ctype.h> extern char *HiSax_getrev(const char *revision); -const char *ni1_revision = "$Revision: 2.8.2.3 $"; +static const char *ni1_revision = "$Revision: 2.8.2.3 $"; #define EXT_BEARER_CAPS 1 @@ -2665,7 +2665,7 @@ static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) l3ni1_SendSpid( pc, pr, arg, 20 ); } -void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) +static void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) { struct sk_buff *skb = arg; diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c index 3ac4484..fe11f22 100644 --- a/drivers/isdn/hisax/mic.c +++ b/drivers/isdn/hisax/mic.c @@ -18,7 +18,7 @@ extern const char *CardType[]; -const char *mic_revision = "$Revision: 1.12.2.4 $"; +static const char *mic_revision = "$Revision: 1.12.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -157,7 +157,7 @@ mic_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_mic(struct IsdnCardState *cs) { int bytecnt = 8; diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index fe61d26..94da03c 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -25,8 +25,6 @@ #include <asm/io.h> #include "netjet.h" -const char *NETjet_revision = "$Revision: 1.29.2.4 $"; - /* Interface functions */ u_char @@ -66,7 +64,7 @@ NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) outsb(cs->hw.njet.isac, data, size); } -void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) +static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) { u_int mask=0x000000ff, val = 0, *p=pos; u_int i; @@ -85,7 +83,7 @@ void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) } } -void +static void mode_tiger(struct BCState *bcs, int mode, int bc) { struct IsdnCardState *cs = bcs->cs; @@ -852,7 +850,7 @@ tiger_l2l1(struct PStack *st, int pr, void *arg) } -void +static void close_tigerstate(struct BCState *bcs) { mode_tiger(bcs, 0, bcs->channel); @@ -900,7 +898,7 @@ open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs) return (0); } -int +static int setstack_tiger(struct PStack *st, struct BCState *bcs) { bcs->channel = st->l1.bc; @@ -966,7 +964,7 @@ inittiger(struct IsdnCardState *cs) cs->bcs[1].BC_Close = close_tigerstate; } -void +static void releasetiger(struct IsdnCardState *cs) { if (cs->bcs[0].hw.tiger.send) { diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index cf77d83..68a2159 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -24,7 +24,7 @@ #include <linux/isapnp.h> extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.21.2.4 $"; +static const char *niccy_revision = "$Revision: 1.21.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -178,7 +178,7 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_niccy(struct IsdnCardState *cs) { if (cs->subtyp == NICCY_PCI) { diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index fd66469..a7d3cd3 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -15,7 +15,7 @@ #include <linux/ppp_defs.h> #include "netjet.h" -const char *NETjet_S_revision = "$Revision: 2.13.2.4 $"; +static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c index 3d6441e..1ae7cac 100644 --- a/drivers/isdn/hisax/nj_u.c +++ b/drivers/isdn/hisax/nj_u.c @@ -15,7 +15,7 @@ #include <linux/ppp_defs.h> #include "netjet.h" -const char *NETjet_U_revision = "$Revision: 2.14.2.3 $"; +static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index 170fcd4..abecabf 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] = {CAUSE_UserInfoDiscarded, "User Info Discarded"} }; -int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); +static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); static int prcause_1tr6(char *dest, u_char * p) @@ -935,7 +935,7 @@ display(char *dest, u_char * p) return (dp - dest); } -int +static int prfacility(char *dest, u_char * p) { char *dp = dest; diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c index f3c4813..7b63085 100644 --- a/drivers/isdn/hisax/s0box.c +++ b/drivers/isdn/hisax/s0box.c @@ -17,7 +17,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *s0box_revision = "$Revision: 2.6.2.4 $"; +static const char *s0box_revision = "$Revision: 2.6.2.4 $"; static inline void writereg(unsigned int padr, signed int addr, u_char off, u_char val) { @@ -183,7 +183,7 @@ s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_s0box(struct IsdnCardState *cs) { release_region(cs->hw.teles3.cfg_reg, 8); diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c index 9e6d3d6..821776e 100644 --- a/drivers/isdn/hisax/saphir.c +++ b/drivers/isdn/hisax/saphir.c @@ -171,7 +171,7 @@ SaphirWatchDog(struct IsdnCardState *cs) mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ); } -void +static void release_io_saphir(struct IsdnCardState *cs) { byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 8390f16..8c044a6 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -51,9 +51,9 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $"; +static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $"; -const char *Sedlbauer_Types[] = +static const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"}; @@ -394,7 +394,7 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_sedlbauer(struct IsdnCardState *cs) { int bytecnt = 8; diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c index 132840b..cdf35dc 100644 --- a/drivers/isdn/hisax/sportster.c +++ b/drivers/isdn/hisax/sportster.c @@ -19,7 +19,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.16.2.4 $"; +static const char *sportster_revision = "$Revision: 1.16.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -132,7 +132,7 @@ sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_sportster(struct IsdnCardState *cs) { int i, adr; @@ -144,7 +144,7 @@ release_io_sportster(struct IsdnCardState *cs) } } -void +static void reset_sportster(struct IsdnCardState *cs) { cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */ diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index e8177b0..0fda5c8 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -450,12 +450,8 @@ int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, usb_complete_t complete, void *context); void st5481_release_isocpipes(struct urb* urb[2]); -int st5481_isoc_flatten(struct urb *urb); void st5481_usb_pipe_reset(struct st5481_adapter *adapter, u_char pipe, ctrl_complete_t complete, void *context); -void st5481_usb_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u8 requesttype, u16 value, u16 index, - ctrl_complete_t complete, void *context); void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, u8 request, u16 value, ctrl_complete_t complete, void *context); diff --git a/drivers/isdn/hisax/st5481_hdlc.c b/drivers/isdn/hisax/st5481_hdlc.c deleted file mode 100644 index 680f42e..0000000 --- a/drivers/isdn/hisax/st5481_hdlc.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/crc-ccitt.h> -#include "st5481_hdlc.h" - - -enum { - HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7, - HDLC_GET_DATA,HDLC_FAST_FLAG -}; - -enum { - HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG, - HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG, - HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0, - HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED -}; - -void -hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56) -{ - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->state = HDLC_GET_DATA; - hdlc->do_adapt56 = do_adapt56; - hdlc->dchannel = 0; - hdlc->crc = 0; - hdlc->cbin = 0; - hdlc->shift_reg = 0; - hdlc->ffvalue = 0; - hdlc->dstpos = 0; -} - -void -hdlc_out_init(struct hdlc_vars *hdlc, int is_d_channel, int do_adapt56) -{ - hdlc->bit_shift = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->ffbit_shift = 0; - hdlc->data_received = 0; - hdlc->do_closing = 0; - hdlc->ffvalue = 0; - if (is_d_channel) { - hdlc->dchannel = 1; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - hdlc->dchannel = 0; - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->ffvalue = 0x7e; - } - hdlc->cbin = 0x7e; - hdlc->bit_shift = 0; - if(do_adapt56){ - hdlc->do_adapt56 = 1; - hdlc->data_bits = 0; - hdlc->state = HDLC_SENDFLAG_B0; - } else { - hdlc->do_adapt56 = 0; - hdlc->data_bits = 8; - } - hdlc->shift_reg = 0; -} - -/* - hdlc_decode - decodes HDLC frames from a transparent bit stream. - - The source buffer is scanned for valid HDLC frames looking for - flags (01111110) to indicate the start of a frame. If the start of - the frame is found, the bit stuffing is removed (0 after 5 1's). - When a new flag is found, the complete frame has been received - and the CRC is checked. - If a valid frame is found, the function returns the frame length - excluding the CRC with the bit HDLC_END_OF_FRAME set. - If the beginning of a valid frame is found, the function returns - the length. - If a framing error is found (too many 1s and not a flag) the function - returns the length with the bit HDLC_FRAMING_ERROR set. - If a CRC error is found the function returns the length with the - bit HDLC_CRC_ERROR set. - If the frame length exceeds the destination buffer size, the function - returns the length with the bit HDLC_LENGTH_ERROR set. - - src - source buffer - slen - source buffer length - count - number of bytes removed (decoded) from the source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of decoded bytes in the destination buffer and status - flag. - */ -int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, - int slen, int *count, unsigned char *dst, int dsize) -{ - int status=0; - - static const unsigned char fast_flag[]={ - 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f - }; - - static const unsigned char fast_flag_value[]={ - 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f - }; - - static const unsigned char fast_abort[]={ - 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff - }; - - *count = slen; - - while(slen > 0){ - if(hdlc->bit_shift==0){ - hdlc->cbin = *src++; - slen--; - hdlc->bit_shift = 8; - if(hdlc->do_adapt56){ - hdlc->bit_shift --; - } - } - - switch(hdlc->state){ - case STOPPED: - return 0; - case HDLC_FAST_IDLE: - if(hdlc->cbin == 0xff){ - hdlc->bit_shift = 0; - break; - } - hdlc->state = HDLC_GET_FLAG_B0; - hdlc->hdlc_bits1 = 0; - hdlc->bit_shift = 8; - break; - case HDLC_GET_FLAG_B0: - if(!(hdlc->cbin & 0x80)) { - hdlc->state = HDLC_GETFLAG_B1A6; - hdlc->hdlc_bits1 = 0; - } else { - if(!hdlc->do_adapt56){ - if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1) - hdlc->state = HDLC_FAST_IDLE; - } - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GETFLAG_B1A6: - if(hdlc->cbin & 0x80){ - hdlc->hdlc_bits1++; - if(hdlc->hdlc_bits1==6){ - hdlc->state = HDLC_GETFLAG_B7; - } - } else { - hdlc->hdlc_bits1 = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GETFLAG_B7: - if(hdlc->cbin & 0x80) { - hdlc->state = HDLC_GET_FLAG_B0; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->hdlc_bits1 = 0; - hdlc->data_bits = 0; - hdlc->data_received = 0; - } - hdlc->cbin<<=1; - hdlc->bit_shift --; - break; - case HDLC_GET_DATA: - if(hdlc->cbin & 0x80){ - hdlc->hdlc_bits1++; - switch(hdlc->hdlc_bits1){ - case 6: - break; - case 7: - if(hdlc->data_received) { - // bad frame - status = -HDLC_FRAMING_ERROR; - } - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=1; - break; - } - } else { - hdlc->state = HDLC_GET_FLAG_B0; - } - break; - default: - hdlc->shift_reg>>=1; - hdlc->shift_reg |= 0x80; - hdlc->data_bits++; - break; - } - } else { - switch(hdlc->hdlc_bits1){ - case 5: - break; - case 6: - if(hdlc->data_received){ - if (hdlc->dstpos < 2) { - status = -HDLC_FRAMING_ERROR; - } else if (hdlc->crc != 0xf0b8){ - // crc error - status = -HDLC_CRC_ERROR; - } else { - // remove CRC - hdlc->dstpos -= 2; - // good frame - status = hdlc->dstpos; - } - } - hdlc->crc = 0xffff; - hdlc->shift_reg = 0; - hdlc->data_bits = 0; - if(!hdlc->do_adapt56){ - if(hdlc->cbin==fast_flag[hdlc->bit_shift]){ - hdlc->ffvalue = fast_flag_value[hdlc->bit_shift]; - hdlc->state = HDLC_FAST_FLAG; - hdlc->ffbit_shift = hdlc->bit_shift; - hdlc->bit_shift = 1; - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } else { - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - break; - default: - hdlc->shift_reg>>=1; - hdlc->data_bits++; - break; - } - hdlc->hdlc_bits1 = 0; - } - if (status) { - hdlc->dstpos = 0; - *count -= slen; - hdlc->cbin <<= 1; - hdlc->bit_shift--; - return status; - } - if(hdlc->data_bits==8){ - hdlc->data_bits = 0; - hdlc->data_received = 1; - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - - // good byte received - if (dsize--) { - dst[hdlc->dstpos++] = hdlc->shift_reg; - } else { - // frame too long - status = -HDLC_LENGTH_ERROR; - hdlc->dstpos = 0; - } - } - hdlc->cbin <<= 1; - hdlc->bit_shift--; - break; - case HDLC_FAST_FLAG: - if(hdlc->cbin==hdlc->ffvalue){ - hdlc->bit_shift = 0; - break; - } else { - if(hdlc->cbin == 0xff){ - hdlc->state = HDLC_FAST_IDLE; - hdlc->bit_shift=0; - } else if(hdlc->ffbit_shift==8){ - hdlc->state = HDLC_GETFLAG_B7; - break; - } else { - hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1]; - hdlc->hdlc_bits1 = hdlc->ffbit_shift-2; - if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0; - hdlc->data_bits = hdlc->ffbit_shift-1; - hdlc->state = HDLC_GET_DATA; - hdlc->data_received = 0; - } - } - break; - default: - break; - } - } - *count -= slen; - return 0; -} - -/* - hdlc_encode - encodes HDLC frames to a transparent bit stream. - - The bit stream starts with a beginning flag (01111110). After - that each byte is added to the bit stream with bit stuffing added - (0 after 5 1's). - When the last byte has been removed from the source buffer, the - CRC (2 bytes is added) and the frame terminates with the ending flag. - For the dchannel, the idle character (all 1's) is also added at the end. - If this function is called with empty source buffer (slen=0), flags or - idle character will be generated. - - src - source buffer - slen - source buffer length - count - number of bytes removed (encoded) from source buffer - dst _ destination buffer - dsize - destination buffer size - returns - number of encoded bytes in the destination buffer -*/ -int hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src, - unsigned short slen, int *count, - unsigned char *dst, int dsize) -{ - static const unsigned char xfast_flag_value[] = { - 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e - }; - - int len = 0; - - *count = slen; - - while (dsize > 0) { - if(hdlc->bit_shift==0){ - if(slen && !hdlc->do_closing){ - hdlc->shift_reg = *src++; - slen--; - if (slen == 0) - hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */ - hdlc->bit_shift = 8; - } else { - if(hdlc->state == HDLC_SEND_DATA){ - if(hdlc->data_received){ - hdlc->state = HDLC_SEND_CRC1; - hdlc->crc ^= 0xffff; - hdlc->bit_shift = 8; - hdlc->shift_reg = hdlc->crc & 0xff; - } else if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - } - } - - } - } - - switch(hdlc->state){ - case STOPPED: - while (dsize--) - *dst++ = 0xff; - - return dsize; - case HDLC_SEND_FAST_FLAG: - hdlc->do_closing = 0; - if(slen == 0){ - *dst++ = hdlc->ffvalue; - len++; - dsize--; - break; - } - if(hdlc->bit_shift==8){ - hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits); - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SENDFLAG_B0: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->hdlc_bits1 = 0; - hdlc->state = HDLC_SENDFLAG_B1A6; - break; - case HDLC_SENDFLAG_B1A6: - hdlc->cbin <<= 1; - hdlc->data_bits++; - hdlc->cbin++; - if(++hdlc->hdlc_bits1 == 6) - hdlc->state = HDLC_SENDFLAG_B7; - break; - case HDLC_SENDFLAG_B7: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(slen == 0){ - hdlc->state = HDLC_SENDFLAG_B0; - break; - } - if(hdlc->bit_shift==8){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - hdlc->data_received = 1; - } - break; - case HDLC_SEND_FIRST_FLAG: - hdlc->data_received = 1; - if(hdlc->data_bits==8){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - break; - } - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->shift_reg & 0x01) - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->state = HDLC_SEND_DATA; - hdlc->crc = 0xffff; - hdlc->hdlc_bits1 = 0; - } - break; - case HDLC_SEND_DATA: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->bit_shift==8){ - hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg); - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - break; - case HDLC_SEND_CRC1: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if(hdlc->bit_shift==0){ - hdlc->shift_reg = (hdlc->crc >> 8); - hdlc->state = HDLC_SEND_CRC2; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CRC2: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->hdlc_bits1++; - hdlc->cbin++; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } else { - hdlc->hdlc_bits1 = 0; - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - } - if(hdlc->bit_shift==0){ - hdlc->shift_reg = 0x7e; - hdlc->state = HDLC_SEND_CLOSING_FLAG; - hdlc->bit_shift = 8; - } - break; - case HDLC_SEND_CLOSING_FLAG: - hdlc->cbin <<= 1; - hdlc->data_bits++; - if(hdlc->hdlc_bits1 == 5){ - hdlc->hdlc_bits1 = 0; - break; - } - if(hdlc->shift_reg & 0x01){ - hdlc->cbin++; - } - hdlc->shift_reg >>= 1; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->ffvalue = xfast_flag_value[hdlc->data_bits]; - if(hdlc->dchannel){ - hdlc->ffvalue = 0x7e; - hdlc->state = HDLC_SEND_IDLE1; - hdlc->bit_shift = 8-hdlc->data_bits; - if(hdlc->bit_shift==0) - hdlc->state = HDLC_SEND_FAST_IDLE; - } else { - if(!hdlc->do_adapt56){ - hdlc->state = HDLC_SEND_FAST_FLAG; - hdlc->data_received = 0; - } else { - hdlc->state = HDLC_SENDFLAG_B0; - hdlc->data_received = 0; - } - // Finished with this frame, send flags - if (dsize > 1) dsize = 1; - } - } - break; - case HDLC_SEND_IDLE1: - hdlc->do_closing = 0; - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - hdlc->bit_shift--; - if(hdlc->bit_shift==0){ - hdlc->state = HDLC_SEND_FAST_IDLE; - hdlc->bit_shift = 0; - } - break; - case HDLC_SEND_FAST_IDLE: - hdlc->do_closing = 0; - hdlc->cbin = 0xff; - hdlc->data_bits = 8; - if(hdlc->bit_shift == 8){ - hdlc->cbin = 0x7e; - hdlc->state = HDLC_SEND_FIRST_FLAG; - } else { - *dst++ = hdlc->cbin; - hdlc->bit_shift = hdlc->data_bits = 0; - len++; - dsize = 0; - } - break; - default: - break; - } - if(hdlc->do_adapt56){ - if(hdlc->data_bits==7){ - hdlc->cbin <<= 1; - hdlc->cbin++; - hdlc->data_bits++; - } - } - if(hdlc->data_bits==8){ - *dst++ = hdlc->cbin; - hdlc->data_bits = 0; - len++; - dsize--; - } - } - *count -= slen; - - return len; -} - diff --git a/drivers/isdn/hisax/st5481_hdlc.h b/drivers/isdn/hisax/st5481_hdlc.h deleted file mode 100644 index 495432f0..0000000 --- a/drivers/isdn/hisax/st5481_hdlc.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __ST5481_HDLC_H__ -#define __ST5481_HDLC_H__ - -struct hdlc_vars { - int bit_shift; - int hdlc_bits1; - int data_bits; - int ffbit_shift; // encoding only - int state; - int dstpos; - - int data_received:1; // set if transferring data - int dchannel:1; // set if D channel (send idle instead of flags) - int do_adapt56:1; // set if 56K adaptation - int do_closing:1; // set if in closing phase (need to send CRC + flag - - unsigned short crc; - - unsigned char cbin; - unsigned char shift_reg; - unsigned char ffvalue; - -}; - - -/* - The return value from hdlc_decode is - the frame length, 0 if no complete frame was decoded, - or a negative error number -*/ - -#define HDLC_FRAMING_ERROR 1 -#define HDLC_CRC_ERROR 2 -#define HDLC_LENGTH_ERROR 3 - -void -hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56); - -int -hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen,int *count, - unsigned char *dst, int dsize); - -void -hdlc_out_init(struct hdlc_vars *hdlc,int is_d_channel,int do_adapt56); - -int -hdlc_encode(struct hdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count, - unsigned char *dst,int dsize); - -#endif diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 2369180..ab62223 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -15,6 +15,8 @@ #include <linux/slab.h> #include "st5481.h" +static int st5481_isoc_flatten(struct urb *urb); + /* ====================================================================== * control pipe */ @@ -55,9 +57,9 @@ static void usb_next_ctrl_msg(struct urb *urb, * Asynchronous endpoint 0 request (async version of usb_control_msg). * The request will be queued up in a FIFO if the endpoint is busy. */ -void usb_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u8 requesttype, u16 value, u16 index, - ctrl_complete_t complete, void *context) +static void usb_ctrl_msg(struct st5481_adapter *adapter, + u8 request, u8 requesttype, u16 value, u16 index, + ctrl_complete_t complete, void *context) { struct st5481_ctrl *ctrl = &adapter->ctrl; int w_index; @@ -571,7 +573,7 @@ void st5481_release_in(struct st5481_in *in) * Make the transfer_buffer contiguous by * copying from the iso descriptors if necessary. */ -int st5481_isoc_flatten(struct urb *urb) +static int st5481_isoc_flatten(struct urb *urb) { struct usb_iso_packet_descriptor *pipd,*pend; unsigned char *src,*dst; diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c index 082726d..ceb0df9 100644 --- a/drivers/isdn/hisax/tei.c +++ b/drivers/isdn/hisax/tei.c @@ -74,7 +74,7 @@ static char *strTeiEvent[] = "EV_T202", }; -unsigned int +static unsigned int random_ri(void) { unsigned int x; diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c index ef8984c..a2b1816 100644 --- a/drivers/isdn/hisax/teleint.c +++ b/drivers/isdn/hisax/teleint.c @@ -18,7 +18,7 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.16.2.5 $"; +static const char *TeleInt_revision = "$Revision: 1.16.2.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -203,7 +203,7 @@ TeleInt_Timer(struct IsdnCardState *cs) add_timer(&cs->hw.hfc.timer); } -void +static void release_io_TeleInt(struct IsdnCardState *cs) { del_timer(&cs->hw.hfc.timer); diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index 5ec5ec3..2b7df8f 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -23,7 +23,7 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.15.2.4 $"; +static const char *teles0_revision = "$Revision: 2.15.2.4 $"; #define TELES_IOMEM_SIZE 0x400 #define byteout(addr,val) outb(val,addr) @@ -183,7 +183,7 @@ teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_teles0(struct IsdnCardState *cs) { if (cs->hw.teles0.cfg_reg) diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c index c5b1f65..adeaad6 100644 --- a/drivers/isdn/hisax/teles3.c +++ b/drivers/isdn/hisax/teles3.c @@ -21,7 +21,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.19.2.4 $"; +static const char *teles3_revision = "$Revision: 2.19.2.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -154,7 +154,7 @@ release_ioregs(struct IsdnCardState *cs, int mask) release_region(cs->hw.teles3.hscx[1] + 32, 32); } -void +static void release_io_teles3(struct IsdnCardState *cs) { if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 0661c6c..e2bb4fd 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -21,7 +21,7 @@ #include <linux/pci.h> extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.23.2.3 $"; +static const char *telespci_revision = "$Revision: 2.23.2.3 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 @@ -257,7 +257,7 @@ telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -void +static void release_io_telespci(struct IsdnCardState *cs) { iounmap(cs->hw.teles0.membase); diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index d2b6b8e..7baf8e4 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -41,7 +41,7 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.18.2.4 $"; +static const char *w6692_revision = "$Revision: 1.18.2.4 $"; #define DBUSY_TIMER_VALUE 80 @@ -880,7 +880,7 @@ setstack_w6692(struct PStack *st, struct BCState *bcs) return (0); } -void resetW6692(struct IsdnCardState *cs) +static void resetW6692(struct IsdnCardState *cs) { cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); mdelay(10); @@ -902,7 +902,7 @@ void resetW6692(struct IsdnCardState *cs) } } -void __init initW6692(struct IsdnCardState *cs, int part) +static void __init initW6692(struct IsdnCardState *cs, int part) { if (part & 1) { cs->setstack_d = setstack_W6692; diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c index 5350836..2cc56d6 100644 --- a/drivers/isdn/i4l/isdn_audio.c +++ b/drivers/isdn/i4l/isdn_audio.c @@ -392,16 +392,6 @@ isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in, } int -isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out) -{ - int olen = 0; - - if (s->nleft) - isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen); - return olen; -} - -int isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in, unsigned char *out, int len) { diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h index 5a977b2..013c358 100644 --- a/drivers/isdn/i4l/isdn_audio.h +++ b/drivers/isdn/i4l/isdn_audio.h @@ -35,7 +35,6 @@ extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out); extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); extern void isdn_audio_eval_dtmf(modem_info *); dtmf_state *isdn_audio_dtmf_init(dtmf_state *); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index c406df6..eebcb0b 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -67,7 +67,7 @@ static isdn_divert_if *divert_if; /* = NULL */ static int isdn_writebuf_stub(int, int, const u_char __user *, int); static void set_global_features(void); static int isdn_wildmat(char *s, char *p); - +static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding); static inline void isdn_lock_driver(isdn_driver_t *drv) @@ -388,7 +388,7 @@ isdn_all_eaz(int di, int ch) */ #include <linux/isdn/capicmd.h> -int +static int isdn_capi_rec_hl_msg(capi_msg *cm) { int di; @@ -1923,7 +1923,7 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) return ret; } -int +static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) { int j, k, m; diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h index 808135c..e27e9c3 100644 --- a/drivers/isdn/i4l/isdn_common.h +++ b/drivers/isdn/i4l/isdn_common.h @@ -41,7 +41,6 @@ extern int isdn_get_free_channel(int, int, int, int, int, char *); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int register_isdn(isdn_if * i); extern int isdn_msncmp( const char *, const char *); -extern int isdn_add_channels(isdn_driver_t *, int, int, int); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); #endif diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c index 83a4f538..0193b6f 100644 --- a/drivers/isdn/i4l/isdn_concap.c +++ b/drivers/isdn/i4l/isdn_concap.c @@ -39,7 +39,7 @@ */ -int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) +static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) { struct net_device *ndev = concap -> net_dev; isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev; @@ -58,7 +58,7 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) } -int isdn_concap_dl_connect_req(struct concap_proto *concap) +static int isdn_concap_dl_connect_req(struct concap_proto *concap) { struct net_device *ndev = concap -> net_dev; isdn_net_local *lp = (isdn_net_local *) ndev->priv; @@ -71,7 +71,7 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap) return ret; } -int isdn_concap_dl_disconn_req(struct concap_proto *concap) +static int isdn_concap_dl_disconn_req(struct concap_proto *concap) { IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name); @@ -85,15 +85,6 @@ struct concap_device_ops isdn_concap_reliable_dl_dops = { &isdn_concap_dl_disconn_req }; -struct concap_device_ops isdn_concap_demand_dial_dops = { - NULL, /* set this first entry to something like &isdn_net_start_xmit, - but the entry part of the current isdn_net_start_xmit must be - separated first. */ - /* no connection control for demand dial semantics */ - NULL, - NULL, -}; - /* The following should better go into a dedicated source file such that this sourcefile does not need to include any protocol specific header files. For now: diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h index 306eb18..6ac7e04 100644 --- a/drivers/isdn/i4l/isdn_concap.h +++ b/drivers/isdn/i4l/isdn_concap.h @@ -8,7 +8,6 @@ */ extern struct concap_device_ops isdn_concap_reliable_dl_dops; -extern struct concap_device_ops isdn_concap_demand_dial_dops; extern struct concap_proto * isdn_concap_new( int ); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index e2b790e..f30e8e6 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -176,7 +176,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) /* Prototypes */ -int isdn_net_force_dial_lp(isdn_net_local *); +static int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); @@ -312,7 +312,7 @@ isdn_net_unbind_channel(isdn_net_local * lp) * Since this function is called every second, simply reset the * byte-counter of the interface after copying it to the cps-variable. */ -unsigned long last_jiffies = -HZ; +static unsigned long last_jiffies = -HZ; void isdn_net_autohup(void) @@ -1131,7 +1131,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) } -void isdn_net_tx_timeout(struct net_device * ndev) +static void isdn_net_tx_timeout(struct net_device * ndev) { isdn_net_local *lp = (isdn_net_local *) ndev->priv; @@ -1424,7 +1424,7 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) } /* cisco hdlck device private ioctls */ -int +static int isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { isdn_net_local *lp = (isdn_net_local *) dev->priv; @@ -2461,7 +2461,7 @@ isdn_net_findif(char *name) * This is called from the userlevel-routine below or * from isdn_net_start_xmit(). */ -int +static int isdn_net_force_dial_lp(isdn_net_local * lp) { if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) { diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index e21007e..ad5aa38 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -273,7 +273,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) return 1; } -void +static void isdn_tty_cleanup_xmit(modem_info * info) { skb_queue_purge(&info->xmit_queue); @@ -560,7 +560,7 @@ isdn_tty_modem_ncarrier(modem_info * info) /* * return the usage calculated by si and layer 2 protocol */ -int +static int isdn_calc_usage(int si, int l2) { int usg = ISDN_USAGE_MODEM; diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h index 2423a7f..9f0fa95 100644 --- a/drivers/isdn/i4l/isdn_tty.h +++ b/drivers/isdn/i4l/isdn_tty.h @@ -109,7 +109,6 @@ extern int isdn_tty_modem_init(void); extern void isdn_tty_exit(void); extern void isdn_tty_readmodem(void); extern int isdn_tty_find_icall(int, int, setup_parm *); -extern void isdn_tty_cleanup_xmit(modem_info *); extern int isdn_tty_stat_callback(int, isdn_ctrl *); extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); extern int isdn_tty_capi_facility(capi_msg *cm); diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c index ce2c3ef..a943d07 100644 --- a/drivers/isdn/i4l/isdn_ttyfax.c +++ b/drivers/isdn/i4l/isdn_ttyfax.c @@ -148,7 +148,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info) } } -int +static int isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c) { static char *msg[] = @@ -316,7 +316,7 @@ isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb) * Parse AT+F.. FAX class 1 commands */ -int +static int isdn_tty_cmd_FCLASS1(char **p, modem_info * info) { static char *cmd[] = @@ -408,7 +408,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info) * Parse AT+F.. FAX class 2 commands */ -int +static int isdn_tty_cmd_FCLASS2(char **p, modem_info * info) { atemu *m = &info->emu; diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c index 4ab7600..edf14a2 100644 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ b/drivers/isdn/i4l/isdn_x25iface.c @@ -40,15 +40,15 @@ typedef struct isdn_x25iface_proto_data { /* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */ -void isdn_x25iface_proto_del( struct concap_proto * ); -int isdn_x25iface_proto_close( struct concap_proto * ); -int isdn_x25iface_proto_restart( struct concap_proto *, - struct net_device *, - struct concap_device_ops *); -int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * ); -int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * ); -int isdn_x25iface_connect_ind( struct concap_proto * ); -int isdn_x25iface_disconn_ind( struct concap_proto * ); +static void isdn_x25iface_proto_del( struct concap_proto * ); +static int isdn_x25iface_proto_close( struct concap_proto * ); +static int isdn_x25iface_proto_restart( struct concap_proto *, + struct net_device *, + struct concap_device_ops *); +static int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * ); +static int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * ); +static int isdn_x25iface_connect_ind( struct concap_proto * ); +static int isdn_x25iface_disconn_ind( struct concap_proto * ); static struct concap_proto_ops ix25_pops = { @@ -102,7 +102,7 @@ struct concap_proto * isdn_x25iface_proto_new(void) /* close the x25iface encapsulation protocol */ -int isdn_x25iface_proto_close(struct concap_proto *cprot){ +static int isdn_x25iface_proto_close(struct concap_proto *cprot){ ix25_pdata_t *tmp; int ret = 0; @@ -129,7 +129,7 @@ int isdn_x25iface_proto_close(struct concap_proto *cprot){ /* Delete the x25iface encapsulation protocol instance */ -void isdn_x25iface_proto_del(struct concap_proto *cprot){ +static void isdn_x25iface_proto_del(struct concap_proto *cprot){ ix25_pdata_t * tmp; @@ -158,9 +158,9 @@ void isdn_x25iface_proto_del(struct concap_proto *cprot){ /* (re-)initialize the data structures for x25iface encapsulation */ -int isdn_x25iface_proto_restart(struct concap_proto *cprot, - struct net_device *ndev, - struct concap_device_ops *dops) +static int isdn_x25iface_proto_restart(struct concap_proto *cprot, + struct net_device *ndev, + struct concap_device_ops *dops) { ix25_pdata_t * pda = cprot -> proto_data ; ulong flags; @@ -187,7 +187,7 @@ int isdn_x25iface_proto_restart(struct concap_proto *cprot, /* deliver a dl_data frame received from i4l HL driver to the network layer */ -int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb) +static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb) { IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) ); if ( ( (ix25_pdata_t*) (cprot->proto_data) ) @@ -206,7 +206,7 @@ int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb) /* a connection set up is indicated by lower layer */ -int isdn_x25iface_connect_ind(struct concap_proto *cprot) +static int isdn_x25iface_connect_ind(struct concap_proto *cprot) { struct sk_buff * skb = dev_alloc_skb(1); enum wan_states *state_p @@ -235,7 +235,7 @@ int isdn_x25iface_connect_ind(struct concap_proto *cprot) /* a disconnect is indicated by lower layer */ -int isdn_x25iface_disconn_ind(struct concap_proto *cprot) +static int isdn_x25iface_disconn_ind(struct concap_proto *cprot) { struct sk_buff *skb; enum wan_states *state_p @@ -264,7 +264,7 @@ int isdn_x25iface_disconn_ind(struct concap_proto *cprot) /* process a frame handed over to us from linux network layer. First byte semantics as defined in Documentation/networking/x25-iface.txt */ -int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb) +static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb) { unsigned char firstbyte = skb->data[0]; enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state; diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c index 692ec72..f151f36 100644 --- a/drivers/isdn/pcbit/callbacks.c +++ b/drivers/isdn/pcbit/callbacks.c @@ -125,23 +125,6 @@ void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, /* - * Disconnect received (actually RELEASE COMPLETE) - * This means we were not able to establish connection with remote - * Inform the big boss above - */ -void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, - struct callb_data *data) -{ - isdn_ctrl ictl; - - ictl.command = ISDN_STAT_DHUP; - ictl.driver=dev->id; - ictl.arg=chan->id; - dev->dev_if->statcallb(&ictl); -} - - -/* * Incoming call received * inform user */ diff --git a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h index f510dc5..17aa0f5 100644 --- a/drivers/isdn/pcbit/callbacks.h +++ b/drivers/isdn/pcbit/callbacks.h @@ -19,9 +19,6 @@ extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data); -extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, - struct callb_data *data); - extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, struct callb_data *data); extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c index 29eb03a..bef321d0 100644 --- a/drivers/isdn/pcbit/capi.c +++ b/drivers/isdn/pcbit/capi.c @@ -627,16 +627,6 @@ int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb) return 0; } -int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb) -{ - ushort errcode; - - errcode = *((ushort*) skb->data); - skb_pull(skb, 2); - - return errcode; -} - #ifdef DEBUG int capi_decode_debug_188(u_char *hdr, ushort hdrlen) { diff --git a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h index 18e6aa3..df8e73c 100644 --- a/drivers/isdn/pcbit/capi.h +++ b/drivers/isdn/pcbit/capi.h @@ -54,7 +54,6 @@ extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb); /* Connection Termination */ extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause); -extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb); extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb); extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb); diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index e98f9c4..5de861f 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -56,10 +56,10 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = { * prototypes */ -int pcbit_command(isdn_ctrl* ctl); -int pcbit_stat(u_char __user * buf, int len, int, int); -int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb); -int pcbit_writecmd(const u_char __user *, int, int, int); +static int pcbit_command(isdn_ctrl* ctl); +static int pcbit_stat(u_char __user * buf, int len, int, int); +static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb); +static int pcbit_writecmd(const u_char __user *, int, int, int); static int set_protocol_running(struct pcbit_dev * dev); @@ -238,7 +238,7 @@ void pcbit_terminate(int board) } #endif -int pcbit_command(isdn_ctrl* ctl) +static int pcbit_command(isdn_ctrl* ctl) { struct pcbit_dev *dev; struct pcbit_chan *chan; @@ -330,7 +330,7 @@ static void pcbit_block_timer(unsigned long data) } #endif -int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb) +static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb) { ushort hdrlen; int refnum, len; @@ -389,7 +389,7 @@ int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb) return len; } -int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel) +static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel) { struct pcbit_dev * dev; int i, j; @@ -713,7 +713,7 @@ static char statbuf[STATBUF_LEN]; static int stat_st = 0; static int stat_end = 0; -int pcbit_stat(u_char __user *buf, int len, int driver, int channel) +static int pcbit_stat(u_char __user *buf, int len, int driver, int channel) { int stat_count; stat_count = stat_end - stat_st; diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile index 9cc474c..0f2b7d6 100644 --- a/drivers/isdn/sc/Makefile +++ b/drivers/isdn/sc/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_ISDN_DRV_SC) += sc.o # Multipart objects. -sc-y := shmem.o init.o debug.o packet.o command.o event.o \ +sc-y := shmem.o init.o packet.o command.o event.o \ ioctl.o interrupt.o message.o timer.o diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c index b2c4eac..19f2fcf 100644 --- a/drivers/isdn/sc/command.c +++ b/drivers/isdn/sc/command.c @@ -22,14 +22,14 @@ #include "card.h" #include "scioc.h" -int dial(int card, unsigned long channel, setup_parm setup); -int hangup(int card, unsigned long channel); -int answer(int card, unsigned long channel); -int clreaz(int card, unsigned long channel); -int seteaz(int card, unsigned long channel, char *); -int setl2(int card, unsigned long arg); -int setl3(int card, unsigned long arg); -int acceptb(int card, unsigned long channel); +static int dial(int card, unsigned long channel, setup_parm setup); +static int hangup(int card, unsigned long channel); +static int answer(int card, unsigned long channel); +static int clreaz(int card, unsigned long channel); +static int seteaz(int card, unsigned long channel, char *); +static int setl2(int card, unsigned long arg); +static int setl3(int card, unsigned long arg); +static int acceptb(int card, unsigned long channel); extern int cinst; extern board *sc_adapter[]; @@ -148,56 +148,6 @@ int command(isdn_ctrl *cmd) } /* - * Confirm our ability to communicate with the board. This test assumes no - * other message activity is present - */ -int loopback(int card) -{ - - int status; - static char testmsg[] = "Test Message"; - RspMessage rspmsg; - - if(!IS_VALID_CARD(card)) { - pr_debug("Invalid param: %d is not a valid card id\n", card); - return -ENODEV; - } - - pr_debug("%s: Sending loopback message\n", - sc_adapter[card]->devicename); - - /* - * Send the loopback message to confirm that memory transfer is - * operational - */ - status = send_and_receive(card, CMPID, cmReqType1, - cmReqClass0, - cmReqMsgLpbk, - 0, - (unsigned char) strlen(testmsg), - (unsigned char *)testmsg, - &rspmsg, SAR_TIMEOUT); - - - if (!status) { - pr_debug("%s: Loopback message successfully sent\n", - sc_adapter[card]->devicename); - if(strcmp(rspmsg.msg_data.byte_array, testmsg)) { - pr_debug("%s: Loopback return != sent\n", - sc_adapter[card]->devicename); - return -EIO; - } - return 0; - } - else { - pr_debug("%s: Send loopback message failed\n", - sc_adapter[card]->devicename); - return -EIO; - } - -} - -/* * start the onboard firmware */ int startproc(int card) @@ -222,16 +172,10 @@ int startproc(int card) } -int loadproc(int card, char *data) -{ - return -1; -} - - /* * Dials the number passed in */ -int dial(int card, unsigned long channel, setup_parm setup) +static int dial(int card, unsigned long channel, setup_parm setup) { int status; char Phone[48]; @@ -261,7 +205,7 @@ int dial(int card, unsigned long channel, setup_parm setup) /* * Answer an incoming call */ -int answer(int card, unsigned long channel) +static int answer(int card, unsigned long channel) { if(!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); @@ -282,7 +226,7 @@ int answer(int card, unsigned long channel) /* * Hangup up the call on specified channel */ -int hangup(int card, unsigned long channel) +static int hangup(int card, unsigned long channel) { int status; @@ -305,7 +249,7 @@ int hangup(int card, unsigned long channel) /* * Set the layer 2 protocol (X.25, HDLC, Raw) */ -int setl2(int card, unsigned long arg) +static int setl2(int card, unsigned long arg) { int status =0; int protocol,channel; @@ -340,7 +284,7 @@ int setl2(int card, unsigned long arg) /* * Set the layer 3 protocol */ -int setl3(int card, unsigned long channel) +static int setl3(int card, unsigned long channel) { int protocol = channel >> 8; @@ -355,7 +299,7 @@ int setl3(int card, unsigned long channel) return 0; } -int acceptb(int card, unsigned long channel) +static int acceptb(int card, unsigned long channel) { if(!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); @@ -374,7 +318,7 @@ int acceptb(int card, unsigned long channel) return 0; } -int clreaz(int card, unsigned long arg) +static int clreaz(int card, unsigned long arg) { if(!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); @@ -388,7 +332,7 @@ int clreaz(int card, unsigned long arg) return 0; } -int seteaz(int card, unsigned long arg, char *num) +static int seteaz(int card, unsigned long arg, char *num) { if(!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c deleted file mode 100644 index 1a992a7..0000000 --- a/drivers/isdn/sc/debug.c +++ /dev/null @@ -1,46 +0,0 @@ -/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $ - * - * Copyright (C) 1996 SpellCaster Telecommunications Inc. - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * For more information, please contact gpl-info@spellcast.com or write: - * - * SpellCaster Telecommunications Inc. - * 5621 Finch Avenue East, Unit #3 - * Scarborough, Ontario Canada - * M1B 2T9 - * +1 (416) 297-8565 - * +1 (416) 297-6433 Facsimile - */ - -#include <linux/kernel.h> -#include <linux/string.h> - -int dbg_level = 0; -static char dbg_funcname[255]; - -void dbg_endfunc(void) -{ - if (dbg_level) { - printk("<-- Leaving function %s\n", dbg_funcname); - strcpy(dbg_funcname, ""); - } -} - -void dbg_func(char *func) -{ - strcpy(dbg_funcname, func); - if(dbg_level) - printk("--> Entering function %s\n", dbg_funcname); -} - -inline void pullphone(char *dn, char *str) -{ - int i = 0; - - while(dn[i] != ',') - str[i] = dn[i], i++; - str[i] = 0x0; -} diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index efefede..40b0df0 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -20,9 +20,9 @@ board *sc_adapter[MAX_CARDS]; int cinst; static char devname[] = "scX"; -const char version[] = "2.0b1"; +static const char version[] = "2.0b1"; -const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; +static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; /* insmod set parameters */ static unsigned int io[] = {0,0,0,0}; @@ -35,26 +35,13 @@ module_param_array(irq, int, NULL, 0); module_param_array(ram, int, NULL, 0); module_param(do_reset, bool, 0); -static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 }; -#define MAX_IRQS 10 - extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *); extern int sndpkt(int, int, int, struct sk_buff *); extern int command(isdn_ctrl *); extern int indicate_status(int, int, ulong, char*); extern int reset(int); -int identify_board(unsigned long, unsigned int); - -int irq_supported(int irq_x) -{ - int i; - for(i=0 ; i < MAX_IRQS ; i++) { - if(sup_irq[i] == irq_x) - return 1; - } - return 0; -} +static int identify_board(unsigned long, unsigned int); static int __init sc_init(void) { @@ -454,7 +441,7 @@ static void __exit sc_exit(void) pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n"); } -int identify_board(unsigned long rambase, unsigned int iobase) +static int identify_board(unsigned long rambase, unsigned int iobase) { unsigned int pgport; unsigned long sig; diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c index e5e164a..8631d33 100644 --- a/drivers/isdn/sc/interrupt.c +++ b/drivers/isdn/sc/interrupt.c @@ -31,7 +31,7 @@ extern void rcvpkt(int, RspMessage *); extern int cinst; extern board *sc_adapter[]; -int get_card_from_irq(int irq) +static int get_card_from_irq(int irq) { int i; diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c index 1371a99..3314a5a 100644 --- a/drivers/isdn/sc/ioctl.c +++ b/drivers/isdn/sc/ioctl.c @@ -14,7 +14,6 @@ extern int indicate_status(int, int, unsigned long, char *); extern int startproc(int); -extern int loadproc(int, char *record); extern int reset(int); extern int send_and_receive(int, unsigned int, unsigned char,unsigned char, unsigned char,unsigned char, @@ -23,7 +22,7 @@ extern int send_and_receive(int, unsigned int, unsigned char,unsigned char, extern board *sc_adapter[]; -int GetStatus(int card, boardInfo *); +static int GetStatus(int card, boardInfo *); /* * Process private IOCTL messages (typically from scctrl) @@ -428,7 +427,7 @@ int sc_ioctl(int card, scs_ioctl *data) return 0; } -int GetStatus(int card, boardInfo *bi) +static int GetStatus(int card, boardInfo *bi) { RspMessage rcvmsg; int i, status; diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c index 8e3fac3..f50defc 100644 --- a/drivers/isdn/sc/packet.c +++ b/drivers/isdn/sc/packet.c @@ -213,19 +213,3 @@ int setup_buffers(int card, int c) return 0; } -int print_skb(int card,char *skb_p, int len){ - int i,data; - pr_debug("%s: data at 0x%x len: 0x%x\n", sc_adapter[card]->devicename, - skb_p,len); - for(i=1;i<=len;i++,skb_p++){ - data = (int) (0xff & (*skb_p)); - pr_debug("%s: data = 0x%x", sc_adapter[card]->devicename,data); - if(!(i%4)) - pr_debug(" "); - if(!(i%32)) - pr_debug("\n"); - } - pr_debug("\n"); - return 0; -} - diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c index 7bc2dfa..24854826 100644 --- a/drivers/isdn/sc/shmem.c +++ b/drivers/isdn/sc/shmem.c @@ -108,6 +108,7 @@ void memcpy_fromshmem(int card, void *dest, const void *src, size_t n) sc_adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */ } +#if 0 void memset_shmem(int card, void *dest, int c, size_t n) { unsigned long flags; @@ -141,3 +142,4 @@ void memset_shmem(int card, void *dest, int c, size_t n) ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80); spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); } +#endif /* 0 */ diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c index 710d0f4..aced19a 100644 --- a/drivers/isdn/sc/timer.c +++ b/drivers/isdn/sc/timer.c @@ -32,7 +32,7 @@ extern int sendmessage(int, unsigned int, unsigned int, unsigned int, /* * Write the proper values into the I/O ports following a reset */ -void setup_ports(int card) +static void setup_ports(int card) { outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]); @@ -129,19 +129,3 @@ void check_phystat(unsigned long data) ceReqPhyStatus,0,0,NULL); } -/* - * When in trace mode, this callback is used to swap the working shared - * RAM page to the trace page(s) and process all received messages. It - * must be called often enough to get all of the messages out of RAM before - * it loops around. - * Trace messages are \n terminated strings. - * We output the messages in 64 byte chunks through readstat. Each chunk - * is scanned for a \n followed by a time stamp. If the timerstamp is older - * than the current time, scanning stops and the page and offset are recorded - * as the starting point the next time the trace timer is called. The final - * step is to restore the working page and reset the timer. - */ -void trace_timer(unsigned long data) -{ - /* not implemented */ -} diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 5ba190c..c9ca111 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -328,9 +328,7 @@ static int monitor_task(void *arg) struct thermostat* th = arg; while(!kthread_should_stop()) { - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); - + try_to_freeze(); msleep_interruptible(2000); #ifndef DEBUG diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c index af56313..0c7bfa7 100644 --- a/drivers/mca/mca-legacy.c +++ b/drivers/mca/mca-legacy.c @@ -180,7 +180,6 @@ struct mca_device *mca_find_device_by_slot(int slot) return info.mca_dev; } -EXPORT_SYMBOL(mca_find_device_by_slot); /** * mca_read_stored_pos - read POS register from boot data diff --git a/drivers/md/md.c b/drivers/md/md.c index 0c6b5b6..3802f7a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2976,8 +2976,7 @@ static int md_thread(void * arg) wait_event_interruptible_timeout(thread->wqueue, test_bit(THREAD_WAKEUP, &thread->flags), thread->timeout); - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); clear_bit(THREAD_WAKEUP, &thread->flags); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index d6b7a9d..f11daae 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -391,8 +391,7 @@ static int dvb_frontend_thread(void *data) break; } - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); if (down_interruptible(&fepriv->sem)) break; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index ac0dc27..867e988 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -435,7 +435,6 @@ struct cx8802_dev { /* ----------------------------------------------------------- */ /* cx88-core.c */ -extern char *cx88_pci_irqs[32]; extern char *cx88_vid_irqs[32]; extern char *cx88_mpeg_irqs[32]; extern void cx88_print_irqbits(char *name, char *tag, char **strings, diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 1b7d38e..b4ee9df 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -750,8 +750,7 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) #endif } } - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); remove_wait_queue(&msp->wq, &wait); return msp->restart; } diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index 5f87007..15f5bb4 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -62,8 +62,7 @@ static int videobuf_dvb_thread(void *data) break; if (kthread_should_stop()) break; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); /* feed buffer data to demux */ if (buf->state == STATE_DONE) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 047202c..5a4a08a 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1606,7 +1606,7 @@ static int rtl8139_thread (void *data) do { timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); /* make swsusp happy with our thread */ - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending (current) && (timeout > 0)); if (signal_pending (current)) { diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c index 18cea10..c650543 100644 --- a/drivers/net/irda/sir_kthread.c +++ b/drivers/net/irda/sir_kthread.c @@ -135,8 +135,7 @@ static int irda_thread(void *startup) remove_wait_queue(&irda_rq_queue.kick, &wait); /* make swsusp happy with our thread */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); run_irda_queue(); } diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 66f488c..15f2073 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -763,7 +763,7 @@ static int stir_transmit_thread(void *arg) { #ifdef CONFIG_PM /* if suspending, then power off and wait */ - if (unlikely(current->flags & PF_FREEZE)) { + if (unlikely(freezing(current))) { if (stir->receiving) receive_stop(stir); else @@ -771,7 +771,7 @@ static int stir_transmit_thread(void *arg) write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); - refrigerator(PF_FREEZE); + refrigerator(); if (change_speed(stir, stir->speed)) break; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a0b8848..7e371b1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -66,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.31" -#define DRV_MODULE_RELDATE "June 8, 2005" +#define DRV_MODULE_VERSION "3.32" +#define DRV_MODULE_RELDATE "June 24, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -337,12 +337,10 @@ static struct { static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) { if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { - unsigned long flags; - - spin_lock_irqsave(&tp->indirect_lock, flags); + spin_lock_bh(&tp->indirect_lock); pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); - spin_unlock_irqrestore(&tp->indirect_lock, flags); + spin_unlock_bh(&tp->indirect_lock); } else { writel(val, tp->regs + off); if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0) @@ -353,12 +351,10 @@ static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) static void _tw32_flush(struct tg3 *tp, u32 off, u32 val) { if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { - unsigned long flags; - - spin_lock_irqsave(&tp->indirect_lock, flags); + spin_lock_bh(&tp->indirect_lock); pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); - spin_unlock_irqrestore(&tp->indirect_lock, flags); + spin_unlock_bh(&tp->indirect_lock); } else { void __iomem *dest = tp->regs + off; writel(val, dest); @@ -398,28 +394,24 @@ static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val) static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) { - unsigned long flags; - - spin_lock_irqsave(&tp->indirect_lock, flags); + spin_lock_bh(&tp->indirect_lock); pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); /* Always leave this as zero. */ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); - spin_unlock_irqrestore(&tp->indirect_lock, flags); + spin_unlock_bh(&tp->indirect_lock); } static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { - unsigned long flags; - - spin_lock_irqsave(&tp->indirect_lock, flags); + spin_lock_bh(&tp->indirect_lock); pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); /* Always leave this as zero. */ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); - spin_unlock_irqrestore(&tp->indirect_lock, flags); + spin_unlock_bh(&tp->indirect_lock); } static void tg3_disable_ints(struct tg3 *tp) @@ -438,12 +430,14 @@ static inline void tg3_cond_int(struct tg3 *tp) static void tg3_enable_ints(struct tg3 *tp) { + tp->irq_sync = 0; + wmb(); + tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, (tp->last_tag << 24)); tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); - tg3_cond_int(tp); } @@ -492,6 +486,7 @@ static void tg3_restart_ints(struct tg3 *tp) static inline void tg3_netif_stop(struct tg3 *tp) { + tp->dev->trans_start = jiffies; /* prevent tx timeout */ netif_poll_disable(tp->dev); netif_tx_disable(tp->dev); } @@ -504,7 +499,8 @@ static inline void tg3_netif_start(struct tg3 *tp) * (such as after tg3_init_hw) */ netif_poll_enable(tp->dev); - tg3_cond_int(tp); + tp->hw_status->status |= SD_STATUS_UPDATED; + tg3_enable_ints(tp); } static void tg3_switch_clocks(struct tg3 *tp) @@ -2578,7 +2574,7 @@ static void tg3_tx(struct tg3 *tp) sw_idx = NEXT_TX(sw_idx); } - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); } tp->tx_cons = sw_idx; @@ -2884,11 +2880,8 @@ static int tg3_poll(struct net_device *netdev, int *budget) { struct tg3 *tp = netdev_priv(netdev); struct tg3_hw_status *sblk = tp->hw_status; - unsigned long flags; int done; - spin_lock_irqsave(&tp->lock, flags); - /* handle link change and other phy events */ if (!(tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | @@ -2896,7 +2889,9 @@ static int tg3_poll(struct net_device *netdev, int *budget) if (sblk->status & SD_STATUS_LINK_CHG) { sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); + spin_lock(&tp->lock); tg3_setup_phy(tp, 0); + spin_unlock(&tp->lock); } } @@ -2907,8 +2902,6 @@ static int tg3_poll(struct net_device *netdev, int *budget) spin_unlock(&tp->tx_lock); } - spin_unlock_irqrestore(&tp->lock, flags); - /* run RX thread, within the bounds set by NAPI. * All RX "locking" is done by ensuring outside * code synchronizes with dev->poll() @@ -2929,19 +2922,54 @@ static int tg3_poll(struct net_device *netdev, int *budget) if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) tp->last_tag = sblk->status_tag; rmb(); + sblk->status &= ~SD_STATUS_UPDATED; /* if no more work, tell net stack and NIC we're done */ done = !tg3_has_work(tp); if (done) { - spin_lock_irqsave(&tp->lock, flags); - __netif_rx_complete(netdev); + spin_lock(&tp->lock); + netif_rx_complete(netdev); tg3_restart_ints(tp); - spin_unlock_irqrestore(&tp->lock, flags); + spin_unlock(&tp->lock); } return (done ? 0 : 1); } +static void tg3_irq_quiesce(struct tg3 *tp) +{ + BUG_ON(tp->irq_sync); + + tp->irq_sync = 1; + smp_mb(); + + synchronize_irq(tp->pdev->irq); +} + +static inline int tg3_irq_sync(struct tg3 *tp) +{ + return tp->irq_sync; +} + +/* Fully shutdown all tg3 driver activity elsewhere in the system. + * If irq_sync is non-zero, then the IRQ handler must be synchronized + * with as well. Most of the time, this is not necessary except when + * shutting down the device. + */ +static inline void tg3_full_lock(struct tg3 *tp, int irq_sync) +{ + if (irq_sync) + tg3_irq_quiesce(tp); + spin_lock_bh(&tp->lock); + spin_lock(&tp->tx_lock); +} + +static inline void tg3_full_unlock(struct tg3 *tp) +{ + spin_unlock(&tp->tx_lock); + spin_unlock_bh(&tp->lock); +} + /* MSI ISR - No need to check for interrupt sharing and no need to * flush status block and interrupt mailbox. PCI ordering rules * guarantee that MSI will arrive after the status block. @@ -2951,9 +2979,6 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); struct tg3_hw_status *sblk = tp->hw_status; - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); /* * Writing any value to intr-mbox-0 clears PCI INTA# and @@ -2964,6 +2989,9 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); tp->last_tag = sblk->status_tag; + rmb(); + if (tg3_irq_sync(tp)) + goto out; sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ @@ -2972,9 +3000,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs) tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, tp->last_tag << 24); } - - spin_unlock_irqrestore(&tp->lock, flags); - +out: return IRQ_RETVAL(1); } @@ -2983,11 +3009,8 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); struct tg3_hw_status *sblk = tp->hw_status; - unsigned long flags; unsigned int handled = 1; - spin_lock_irqsave(&tp->lock, flags); - /* In INTx mode, it is possible for the interrupt to arrive at * the CPU before the status block posted prior to the interrupt. * Reading the PCI State register will confirm whether the @@ -3004,6 +3027,8 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + if (tg3_irq_sync(tp)) + goto out; sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ @@ -3018,9 +3043,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) } else { /* shared interrupt */ handled = 0; } - - spin_unlock_irqrestore(&tp->lock, flags); - +out: return IRQ_RETVAL(handled); } @@ -3029,11 +3052,8 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r struct net_device *dev = dev_id; struct tg3 *tp = netdev_priv(dev); struct tg3_hw_status *sblk = tp->hw_status; - unsigned long flags; unsigned int handled = 1; - spin_lock_irqsave(&tp->lock, flags); - /* In INTx mode, it is possible for the interrupt to arrive at * the CPU before the status block posted prior to the interrupt. * Reading the PCI State register will confirm whether the @@ -3051,6 +3071,9 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); tp->last_tag = sblk->status_tag; + rmb(); + if (tg3_irq_sync(tp)) + goto out; sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) netif_rx_schedule(dev); /* schedule NAPI poll */ @@ -3065,9 +3088,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r } else { /* shared interrupt */ handled = 0; } - - spin_unlock_irqrestore(&tp->lock, flags); - +out: return IRQ_RETVAL(handled); } @@ -3106,8 +3127,7 @@ static void tg3_reset_task(void *_data) tg3_netif_stop(tp); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 1); restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; @@ -3117,8 +3137,7 @@ static void tg3_reset_task(void *_data) tg3_netif_start(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); if (restart_timer) mod_timer(&tp->timer, jiffies + 1); @@ -3224,39 +3243,21 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int i; u32 len, entry, base_flags, mss; int would_hit_hwbug; - unsigned long flags; len = skb_headlen(skb); /* No BH disabling for tx_lock here. We are running in BH disabled * context and TX reclaim runs via tp->poll inside of a software - * interrupt. Rejoice! - * - * Actually, things are not so simple. If we are to take a hw - * IRQ here, we can deadlock, consider: - * - * CPU1 CPU2 - * tg3_start_xmit - * take tp->tx_lock - * tg3_timer - * take tp->lock - * tg3_interrupt - * spin on tp->lock - * spin on tp->tx_lock - * - * So we really do need to disable interrupts when taking - * tx_lock here. + * interrupt. Furthermore, IRQ processing runs lockless so we have + * no IRQ context deadlocks to worry about either. Rejoice! */ - local_irq_save(flags); - if (!spin_trylock(&tp->tx_lock)) { - local_irq_restore(flags); + if (!spin_trylock(&tp->tx_lock)) return NETDEV_TX_LOCKED; - } /* This is a hard error, log it. */ if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { netif_stop_queue(dev); - spin_unlock_irqrestore(&tp->tx_lock, flags); + spin_unlock(&tp->tx_lock); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); return NETDEV_TX_BUSY; @@ -3421,7 +3422,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) out_unlock: mmiowb(); - spin_unlock_irqrestore(&tp->tx_lock, flags); + spin_unlock(&tp->tx_lock); dev->trans_start = jiffies; @@ -3455,8 +3456,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) } tg3_netif_stop(tp); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + + tg3_full_lock(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -3466,8 +3467,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_netif_start(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); return 0; } @@ -5088,9 +5088,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - spin_lock_irq(&tp->lock); + spin_lock_bh(&tp->lock); __tg3_set_mac_addr(tp); - spin_unlock_irq(&tp->lock); + spin_unlock_bh(&tp->lock); return 0; } @@ -5727,9 +5727,6 @@ static int tg3_reset_hw(struct tg3 *tp) tg3_write_sig_post_reset(tp, RESET_KIND_INIT); - if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) - tg3_enable_ints(tp); - return 0; } @@ -5802,10 +5799,8 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque; - unsigned long flags; - spin_lock_irqsave(&tp->lock, flags); - spin_lock(&tp->tx_lock); + spin_lock(&tp->lock); if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { /* All of this garbage is because when using non-tagged @@ -5822,8 +5817,7 @@ static void tg3_timer(unsigned long __opaque) if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; - spin_unlock(&tp->tx_lock); - spin_unlock_irqrestore(&tp->lock, flags); + spin_unlock(&tp->lock); schedule_work(&tp->reset_task); return; } @@ -5891,8 +5885,7 @@ static void tg3_timer(unsigned long __opaque) tp->asf_counter = tp->asf_multiplier; } - spin_unlock(&tp->tx_lock); - spin_unlock_irqrestore(&tp->lock, flags); + spin_unlock(&tp->lock); tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); @@ -6007,14 +6000,12 @@ static int tg3_test_msi(struct tg3 *tp) /* Need to reset the chip because the MSI cycle may have terminated * with Master Abort. */ - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); err = tg3_init_hw(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); if (err) free_irq(tp->pdev->irq, dev); @@ -6027,14 +6018,12 @@ static int tg3_open(struct net_device *dev) struct tg3 *tp = netdev_priv(dev); int err; - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); tg3_disable_ints(tp); tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); /* The placement of this call is tied * to the setup and use of Host TX descriptors. @@ -6081,8 +6070,7 @@ static int tg3_open(struct net_device *dev) return err; } - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); err = tg3_init_hw(tp); if (err) { @@ -6106,8 +6094,7 @@ static int tg3_open(struct net_device *dev) tp->timer.function = tg3_timer; } - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); if (err) { free_irq(tp->pdev->irq, dev); @@ -6123,8 +6110,7 @@ static int tg3_open(struct net_device *dev) err = tg3_test_msi(tp); if (err) { - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { pci_disable_msi(tp->pdev); @@ -6134,22 +6120,19 @@ static int tg3_open(struct net_device *dev) tg3_free_rings(tp); tg3_free_consistent(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); return err; } } - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); add_timer(&tp->timer); tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tg3_enable_ints(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); netif_start_queue(dev); @@ -6395,8 +6378,7 @@ static int tg3_close(struct net_device *dev) del_timer_sync(&tp->timer); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 1); #if 0 tg3_dump_state(tp); #endif @@ -6410,8 +6392,7 @@ static int tg3_close(struct net_device *dev) TG3_FLAG_GOT_SERDES_FLOWCTL); netif_carrier_off(tp->dev); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); free_irq(tp->pdev->irq, dev); if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -6448,16 +6429,15 @@ static unsigned long calc_crc_errors(struct tg3 *tp) if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { - unsigned long flags; u32 val; - spin_lock_irqsave(&tp->lock, flags); + spin_lock_bh(&tp->lock); if (!tg3_readphy(tp, 0x1e, &val)) { tg3_writephy(tp, 0x1e, val | 0x8000); tg3_readphy(tp, 0x14, &val); } else val = 0; - spin_unlock_irqrestore(&tp->lock, flags); + spin_unlock_bh(&tp->lock); tp->phy_crc_errors += val; @@ -6719,11 +6699,9 @@ static void tg3_set_rx_mode(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); __tg3_set_rx_mode(dev); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); } #define TG3_REGDUMP_LEN (32 * 1024) @@ -6745,8 +6723,7 @@ static void tg3_get_regs(struct net_device *dev, memset(p, 0, TG3_REGDUMP_LEN); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); #define __GET_REG32(reg) (*(p)++ = tr32(reg)) #define GET_REG32_LOOP(base,len) \ @@ -6796,8 +6773,7 @@ do { p = (u32 *)(orig_p + (reg)); \ #undef GET_REG32_LOOP #undef GET_REG32_1 - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); } static int tg3_get_eeprom_len(struct net_device *dev) @@ -6973,8 +6949,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); tp->link_config.autoneg = cmd->autoneg; if (cmd->autoneg == AUTONEG_ENABLE) { @@ -6990,8 +6965,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (netif_running(dev)) tg3_setup_phy(tp, 1); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); return 0; } @@ -7027,12 +7001,12 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP)) return -EINVAL; - spin_lock_irq(&tp->lock); + spin_lock_bh(&tp->lock); if (wol->wolopts & WAKE_MAGIC) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; else tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; - spin_unlock_irq(&tp->lock); + spin_unlock_bh(&tp->lock); return 0; } @@ -7072,7 +7046,7 @@ static int tg3_nway_reset(struct net_device *dev) if (!netif_running(dev)) return -EAGAIN; - spin_lock_irq(&tp->lock); + spin_lock_bh(&tp->lock); r = -EINVAL; tg3_readphy(tp, MII_BMCR, &bmcr); if (!tg3_readphy(tp, MII_BMCR, &bmcr) && @@ -7080,7 +7054,7 @@ static int tg3_nway_reset(struct net_device *dev) tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART); r = 0; } - spin_unlock_irq(&tp->lock); + spin_unlock_bh(&tp->lock); return r; } @@ -7102,17 +7076,19 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct tg3 *tp = netdev_priv(dev); + int irq_sync = 0; if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) || (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || (ering->tx_pending > TG3_TX_RING_SIZE - 1)) return -EINVAL; - if (netif_running(dev)) + if (netif_running(dev)) { tg3_netif_stop(tp); + irq_sync = 1; + } - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, irq_sync); tp->rx_pending = ering->rx_pending; @@ -7128,8 +7104,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tg3_netif_start(tp); } - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); return 0; } @@ -7146,12 +7121,15 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { struct tg3 *tp = netdev_priv(dev); + int irq_sync = 0; - if (netif_running(dev)) + if (netif_running(dev)) { tg3_netif_stop(tp); + irq_sync = 1; + } + + tg3_full_lock(tp, irq_sync); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); if (epause->autoneg) tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; else @@ -7170,8 +7148,8 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tg3_init_hw(tp); tg3_netif_start(tp); } - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + + tg3_full_unlock(tp); return 0; } @@ -7192,12 +7170,12 @@ static int tg3_set_rx_csum(struct net_device *dev, u32 data) return 0; } - spin_lock_irq(&tp->lock); + spin_lock_bh(&tp->lock); if (data) tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; else tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; - spin_unlock_irq(&tp->lock); + spin_unlock_bh(&tp->lock); return 0; } @@ -7606,8 +7584,6 @@ static int tg3_test_loopback(struct tg3 *tp) tg3_abort_hw(tp, 1); - /* Clearing this flag to keep interrupts disabled */ - tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tg3_reset_hw(tp); mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | @@ -7716,11 +7692,14 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, data[1] = 1; } if (etest->flags & ETH_TEST_FL_OFFLINE) { - if (netif_running(dev)) + int irq_sync = 0; + + if (netif_running(dev)) { tg3_netif_stop(tp); + irq_sync = 1; + } - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, irq_sync); tg3_halt(tp, RESET_KIND_SUSPEND, 1); tg3_nvram_lock(tp); @@ -7742,14 +7721,14 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, data[4] = 1; } - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); + if (tg3_test_interrupt(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[5] = 1; } - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + + tg3_full_lock(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { @@ -7757,8 +7736,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_init_hw(tp); tg3_netif_start(tp); } - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + + tg3_full_unlock(tp); } } @@ -7779,9 +7758,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ - spin_lock_irq(&tp->lock); + spin_lock_bh(&tp->lock); err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval); - spin_unlock_irq(&tp->lock); + spin_unlock_bh(&tp->lock); data->val_out = mii_regval; @@ -7795,9 +7774,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irq(&tp->lock); + spin_lock_bh(&tp->lock); err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in); - spin_unlock_irq(&tp->lock); + spin_unlock_bh(&tp->lock); return err; @@ -7813,28 +7792,24 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { struct tg3 *tp = netdev_priv(dev); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); tp->vlgrp = grp; /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */ __tg3_set_rx_mode(dev); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); } static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct tg3 *tp = netdev_priv(dev); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); if (tp->vlgrp) tp->vlgrp->vlan_devices[vid] = NULL; - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); } #endif @@ -10165,24 +10140,19 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) del_timer_sync(&tp->timer); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 1); tg3_disable_ints(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); netif_device_detach(dev); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); if (err) { - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); tg3_init_hw(tp); @@ -10192,8 +10162,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_attach(dev); tg3_netif_start(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); } return err; @@ -10216,20 +10185,16 @@ static int tg3_resume(struct pci_dev *pdev) netif_device_attach(dev); - spin_lock_irq(&tp->lock); - spin_lock(&tp->tx_lock); + tg3_full_lock(tp, 0); tg3_init_hw(tp); tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); - tg3_enable_ints(tp); - tg3_netif_start(tp); - spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + tg3_full_unlock(tp); return 0; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 993f84c..99c5f96 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2006,17 +2006,31 @@ struct tg3_ethtool_stats { struct tg3 { /* begin "general, frequently-used members" cacheline section */ + /* If the IRQ handler (which runs lockless) needs to be + * quiesced, the following bitmask state is used. The + * SYNC flag is set by non-IRQ context code to initiate + * the quiescence. + * + * When the IRQ handler notices that SYNC is set, it + * disables interrupts and returns. + * + * When all outstanding IRQ handlers have returned after + * the SYNC flag has been set, the setter can be assured + * that interrupts will no longer get run. + * + * In this way all SMP driver locks are never acquired + * in hw IRQ context, only sw IRQ context or lower. + */ + unsigned int irq_sync; + /* SMP locking strategy: * * lock: Held during all operations except TX packet * processing. * - * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx + * tx_lock: Held during tg3_start_xmit and tg3_tx * - * If you want to shut up all asynchronous processing you must - * acquire both locks, 'lock' taken before 'tx_lock'. IRQs must - * be disabled to take 'lock' but only softirq disabling is - * necessary for acquisition of 'tx_lock'. + * Both of these locks are to be held with BH safety. */ spinlock_t lock; spinlock_t indirect_lock; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 66b9466..18c27e1 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -435,7 +435,7 @@ config VENDOR_SANGOMA the driver to support. If you have one or more of these cards, say M to this option; - and read <file:Documentation/networking/wanpipe.txt>. + and read <file:Documentation/networking/wan-router.txt>. To compile this driver as a module, choose M here: the module will be called wanpipe. diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index fb10a2d..d72e038 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2918,7 +2918,7 @@ static int airo_thread(void *data) { flush_signals(current); /* make swsusp happy with our thread */ - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (test_bit(JOB_DIE, &ai->flags)) break; diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index d136b3c..48e4f04 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -718,7 +718,7 @@ static int pccardd(void *__skt) } schedule(); - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (!skt->thread) break; diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index e939c93..778a324 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -182,7 +182,7 @@ static int pnp_dock_thread(void * unused) msleep_interruptible(2000); if(signal_pending(current)) { - if (try_to_freeze(PF_FREEZE)) + if (try_to_freeze()) continue; break; } diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig index 96413c2..a86a650 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/Kconfig @@ -187,6 +187,13 @@ config VMLOGRDR *SYMPTOM. This driver depends on the IUCV support driver. +config VMCP + tristate "Support for the z/VM CP interface (VM only)" + help + Select this option if you want to be able to interact with the control + program on z/VM + + config MONREADER tristate "API for reading z/VM monitor service records" depends on IUCV diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index ceeb3cf..6527ff6 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -176,7 +176,7 @@ dasd_state_known_to_basic(struct dasd_device * device) return rc; /* register 'device' debug area, used for all DBF_DEV_XXX calls */ - device->debug_area = debug_register(device->cdev->dev.bus_id, 0, 2, + device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2, 8 * sizeof (long)); debug_register_view(device->debug_area, &debug_sprintf_view); debug_set_level(device->debug_area, DBF_EMERG); @@ -1952,26 +1952,24 @@ dasd_generic_notify(struct ccw_device *cdev, int event) * Automatically online either all dasd devices (dasd_autodetect) or * all devices specified with dasd= parameters. */ +static int +__dasd_auto_online(struct device *dev, void *data) +{ + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); + if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) + ccw_device_set_online(cdev); + return 0; +} + void dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) { struct device_driver *drv; - struct device *d, *dev; - struct ccw_device *cdev; drv = get_driver(&dasd_discipline_driver->driver); - down_read(&drv->bus->subsys.rwsem); - dev = NULL; - list_for_each_entry(d, &drv->devices, driver_list) { - dev = get_device(d); - if (!dev) - continue; - cdev = to_ccwdev(dev); - if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) - ccw_device_set_online(cdev); - put_device(dev); - } - up_read(&drv->bus->subsys.rwsem); + driver_for_each_device(drv, NULL, NULL, __dasd_auto_online); put_driver(drv); } @@ -1983,7 +1981,7 @@ dasd_init(void) init_waitqueue_head(&dasd_init_waitq); /* register 'common' DASD debug area, used for all DBF_XXX calls */ - dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long)); + dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long)); if (dasd_debug_area == NULL) { rc = -ENOMEM; goto failed; diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index d7f1974..43c34f8 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -9,13 +9,14 @@ * * /proc interface for the dasd driver. * - * $Revision: 1.31 $ + * $Revision: 1.32 $ */ #include <linux/config.h> #include <linux/ctype.h> #include <linux/seq_file.h> #include <linux/vmalloc.h> +#include <linux/proc_fs.h> #include <asm/debug.h> #include <asm/uaccess.h> diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 6bc27d5..4fde411 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -718,7 +718,7 @@ dcssblk_check_params(void) buf[j-i] = dcssblk_segments[j]; } buf[j-i] = '\0'; - rc = dcssblk_add_store(dcssblk_root_dev, buf, j-i); + rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); if ((rc >= 0) && (dcssblk_segments[j] == '(')) { for (k = 0; buf[k] != '\0'; k++) buf[k] = toupper(buf[k]); @@ -728,7 +728,7 @@ dcssblk_check_params(void) up_read(&dcssblk_devices_sem); if (dev_info) dcssblk_shared_store(&dev_info->dev, - "0\n", 2); + NULL, "0\n", 2); } } while ((dcssblk_segments[j] != ',') && diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 14e8cce..6377a96 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o +obj-$(CONFIG_VMCP) += vmcp.o tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o tape-$(CONFIG_PROC_FS) += tape_proc.o diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 022f17b..f11a67f 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -860,8 +860,8 @@ con3215_init(void) /* Set the console mode for VM */ if (MACHINE_IS_VM) { - cpcmd("TERM CONMODE 3215", NULL, 0); - cpcmd("TERM AUTOCR OFF", NULL, 0); + cpcmd("TERM CONMODE 3215", NULL, 0, NULL); + cpcmd("TERM AUTOCR OFF", NULL, 0, NULL); } /* allocate 3215 request structures */ diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index d52fb57..fc7a213 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -591,8 +591,8 @@ con3270_init(void) /* Set the console mode for VM */ if (MACHINE_IS_VM) { - cpcmd("TERM CONMODE 3270", 0, 0); - cpcmd("TERM AUTOCR OFF", 0, 0); + cpcmd("TERM CONMODE 3270", NULL, 0, NULL); + cpcmd("TERM AUTOCR OFF", NULL, 0, NULL); } cdev = ccw_device_probe_console(); diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 480ec87..20be88e 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1351,13 +1351,13 @@ tape_34xx_init (void) { int rc; - TAPE_DBF_AREA = debug_register ( "tape_34xx", 1, 2, 4*sizeof(long)); + TAPE_DBF_AREA = debug_register ( "tape_34xx", 2, 2, 4*sizeof(long)); debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); #ifdef DBF_LIKE_HELL debug_set_level(TAPE_DBF_AREA, 6); #endif - DBF_EVENT(3, "34xx init: $Revision: 1.21 $\n"); + DBF_EVENT(3, "34xx init: $Revision: 1.23 $\n"); /* Register driver for 3480/3490 tapes. */ rc = ccw_driver_register(&tape_34xx_driver); if (rc) @@ -1378,7 +1378,7 @@ tape_34xx_exit(void) MODULE_DEVICE_TABLE(ccw, tape_34xx_ids); MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH"); MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape " - "device driver ($Revision: 1.21 $)"); + "device driver ($Revision: 1.23 $)"); MODULE_LICENSE("GPL"); module_init(tape_34xx_init); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index b4df4a5..0597aa0 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -1186,7 +1186,7 @@ tape_mtop(struct tape_device *device, int mt_op, int mt_count) static int tape_init (void) { - TAPE_DBF_AREA = debug_register ( "tape", 1, 2, 4*sizeof(long)); + TAPE_DBF_AREA = debug_register ( "tape", 2, 2, 4*sizeof(long)); debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); #ifdef DBF_LIKE_HELL debug_set_level(TAPE_DBF_AREA, 6); diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index 801d17c..5fec0a1 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/seq_file.h> +#include <linux/proc_fs.h> #define TAPE_DBF_AREA tape_core_dbf diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c new file mode 100644 index 0000000..7f11a60 --- /dev/null +++ b/drivers/s390/char/vmcp.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2004,2005 IBM Corporation + * Interface implementation for communication with the v/VM control program + * Author(s): Christian Borntraeger <cborntra@de.ibm.com> + * + * + * z/VMs CP offers the possibility to issue commands via the diagnose code 8 + * this driver implements a character device that issues these commands and + * returns the answer of CP. + + * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS + */ + +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <asm/cpcmd.h> +#include <asm/debug.h> +#include <asm/uaccess.h> +#include "vmcp.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>"); +MODULE_DESCRIPTION("z/VM CP interface"); + +static debug_info_t *vmcp_debug; + +static int vmcp_open(struct inode *inode, struct file *file) +{ + struct vmcp_session *session; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + session = kmalloc(sizeof(*session), GFP_KERNEL); + if (!session) + return -ENOMEM; + session->bufsize = PAGE_SIZE; + session->response = NULL; + session->resp_size = 0; + init_MUTEX(&session->mutex); + file->private_data = session; + return nonseekable_open(inode, file); +} + +static int vmcp_release(struct inode *inode, struct file *file) +{ + struct vmcp_session *session; + + session = (struct vmcp_session *)file->private_data; + file->private_data = NULL; + free_pages((unsigned long)session->response, get_order(session->bufsize)); + kfree(session); + return 0; +} + +static ssize_t +vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos) +{ + size_t tocopy; + struct vmcp_session *session; + + session = (struct vmcp_session *)file->private_data; + if (down_interruptible(&session->mutex)) + return -ERESTARTSYS; + if (!session->response) { + up(&session->mutex); + return 0; + } + if (*ppos > session->resp_size) { + up(&session->mutex); + return 0; + } + tocopy = min(session->resp_size - (size_t) (*ppos), count); + tocopy = min(tocopy,session->bufsize - (size_t) (*ppos)); + + if (copy_to_user(buff, session->response + (*ppos), tocopy)) { + up(&session->mutex); + return -EFAULT; + } + up(&session->mutex); + *ppos += tocopy; + return tocopy; +} + +static ssize_t +vmcp_write(struct file *file, const char __user * buff, size_t count, + loff_t * ppos) +{ + char *cmd; + struct vmcp_session *session; + + if (count > 240) + return -EINVAL; + cmd = kmalloc(count + 1, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + if (copy_from_user(cmd, buff, count)) { + kfree(cmd); + return -EFAULT; + } + cmd[count] = '\0'; + session = (struct vmcp_session *)file->private_data; + if (down_interruptible(&session->mutex)) + return -ERESTARTSYS; + if (!session->response) + session->response = (char *)__get_free_pages(GFP_KERNEL + | __GFP_REPEAT | GFP_DMA, + get_order(session->bufsize)); + if (!session->response) { + up(&session->mutex); + kfree(cmd); + return -ENOMEM; + } + debug_text_event(vmcp_debug, 1, cmd); + session->resp_size = cpcmd(cmd, session->response, + session->bufsize, + &session->resp_code); + up(&session->mutex); + kfree(cmd); + *ppos = 0; /* reset the file pointer after a command */ + return count; +} + + +/* + * These ioctls are available, as the semantics of the diagnose 8 call + * does not fit very well into a Linux call. Diagnose X'08' is described in + * CP Programming Services SC24-6084-00 + * + * VMCP_GETCODE: gives the CP return code back to user space + * VMCP_SETBUF: sets the response buffer for the next write call. diagnose 8 + * expects adjacent pages in real storage and to make matters worse, we + * dont know the size of the response. Therefore we default to PAGESIZE and + * let userspace to change the response size, if userspace expects a bigger + * response + */ +static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct vmcp_session *session; + int temp; + + session = (struct vmcp_session *)file->private_data; + if (down_interruptible(&session->mutex)) + return -ERESTARTSYS; + switch (cmd) { + case VMCP_GETCODE: + temp = session->resp_code; + up(&session->mutex); + return put_user(temp, (int __user *)arg); + case VMCP_SETBUF: + free_pages((unsigned long)session->response, + get_order(session->bufsize)); + session->response=NULL; + temp = get_user(session->bufsize, (int __user *)arg); + if (get_order(session->bufsize) > 8) { + session->bufsize = PAGE_SIZE; + temp = -EINVAL; + } + up(&session->mutex); + return temp; + case VMCP_GETSIZE: + temp = session->resp_size; + up(&session->mutex); + return put_user(temp, (int __user *)arg); + default: + up(&session->mutex); + return -ENOIOCTLCMD; + } +} + +static struct file_operations vmcp_fops = { + .owner = THIS_MODULE, + .open = &vmcp_open, + .release = &vmcp_release, + .read = &vmcp_read, + .llseek = &no_llseek, + .write = &vmcp_write, + .unlocked_ioctl = &vmcp_ioctl, + .compat_ioctl = &vmcp_ioctl +}; + +static struct miscdevice vmcp_dev = { + .name = "vmcp", + .minor = MISC_DYNAMIC_MINOR, + .fops = &vmcp_fops, +}; + +static int __init vmcp_init(void) +{ + int ret; + + if (!MACHINE_IS_VM) { + printk(KERN_WARNING + "z/VM CP interface is only available under z/VM\n"); + return -ENODEV; + } + ret = misc_register(&vmcp_dev); + if (!ret) + printk(KERN_INFO "z/VM CP interface loaded\n"); + else + printk(KERN_WARNING + "z/VM CP interface not loaded. Could not register misc device.\n"); + vmcp_debug = debug_register("vmcp", 1, 1, 240); + debug_register_view(vmcp_debug, &debug_hex_ascii_view); + return ret; +} + +static void __exit vmcp_exit(void) +{ + WARN_ON(misc_deregister(&vmcp_dev) != 0); + debug_unregister(vmcp_debug); + printk(KERN_INFO "z/VM CP interface unloaded.\n"); +} + +module_init(vmcp_init); +module_exit(vmcp_exit); diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h new file mode 100644 index 0000000..87389e7 --- /dev/null +++ b/drivers/s390/char/vmcp.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2004, 2005 IBM Corporation + * Interface implementation for communication with the v/VM control program + * Version 1.0 + * Author(s): Christian Borntraeger <cborntra@de.ibm.com> + * + * + * z/VMs CP offers the possibility to issue commands via the diagnose code 8 + * this driver implements a character device that issues these commands and + * returns the answer of CP. + * + * The idea of this driver is based on cpint from Neale Ferguson + */ + +#include <asm/semaphore.h> +#include <linux/ioctl.h> + +#define VMCP_GETCODE _IOR(0x10, 1, int) +#define VMCP_SETBUF _IOW(0x10, 2, int) +#define VMCP_GETSIZE _IOR(0x10, 3, int) + +struct vmcp_session { + unsigned int bufsize; + char *response; + int resp_size; + int resp_code; + /* As we use copy_from/to_user, which might * + * sleep and cannot use a spinlock */ + struct semaphore mutex; +}; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index f771732..491f00c 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -236,7 +236,7 @@ vmlogrdr_get_recording_class_AB(void) { int len,i; printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response); len = strnlen(cp_response,sizeof(cp_response)); // now the parsing @@ -288,7 +288,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: recording response: %s", cp_response); } @@ -301,7 +301,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { qid_string); printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: recording response: %s", cp_response); /* The recording command will usually answer with 'Command complete' @@ -607,7 +607,7 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c priv->recording_name); printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); - cpcmd(cp_command, cp_response, sizeof(cp_response)); + cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); printk (KERN_DEBUG "vmlogrdr: recording response: %s", cp_response); @@ -682,7 +682,7 @@ vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { char cp_command[] = "QUERY RECORDING "; int len; - cpcmd(cp_command, buf, 4096); + cpcmd(cp_command, buf, 4096, NULL); len = strlen(buf); return len; } diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 306525ac..91ea8e4 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -403,34 +403,22 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver) return driver_register(&cdriver->driver); } -static inline struct device * -__get_next_ccwgroup_device(struct device_driver *drv) +static int +__ccwgroup_driver_unregister_device(struct device *dev, void *data) { - struct device *dev, *d; - - down_read(&drv->bus->subsys.rwsem); - dev = NULL; - list_for_each_entry(d, &drv->devices, driver_list) { - dev = get_device(d); - if (dev) - break; - } - up_read(&drv->bus->subsys.rwsem); - return dev; + __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); + device_unregister(dev); + put_device(dev); + return 0; } void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) { - struct device *dev; - /* We don't want ccwgroup devices to live longer than their driver. */ get_driver(&cdriver->driver); - while ((dev = __get_next_ccwgroup_device(&cdriver->driver))) { - __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); - device_unregister(dev); - put_device(dev); - }; + driver_for_each_device(&cdriver->driver, NULL, NULL, + __ccwgroup_driver_unregister_device); put_driver(&cdriver->driver); driver_unregister(&cdriver->driver); } @@ -449,7 +437,7 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) if (cdev->dev.driver_data) { gdev = (struct ccwgroup_device *)cdev->dev.driver_data; if (get_device(&gdev->dev)) { - if (!list_empty(&gdev->dev.node)) + if (klist_node_attached(&gdev->dev.knode_bus)) return gdev; put_device(&gdev->dev); } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 1d9b3f1..ea813bd 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls - * $Revision: 1.133 $ + * $Revision: 1.134 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -63,17 +63,17 @@ __setup ("cio_msg=", cio_setup); static int __init cio_debug_init (void) { - cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16*sizeof (long)); + cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long)); if (!cio_debug_msg_id) goto out_unregister; debug_register_view (cio_debug_msg_id, &debug_sprintf_view); debug_set_level (cio_debug_msg_id, 2); - cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8); + cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 8); if (!cio_debug_trace_id) goto out_unregister; debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); debug_set_level (cio_debug_trace_id, 2); - cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long)); + cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long)); if (!cio_debug_crw_id) goto out_unregister; debug_register_view (cio_debug_crw_id, &debug_sprintf_view); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 87bd70e..555119c 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -128,34 +128,28 @@ css_probe_device(int irq) return ret; } +static int +check_subchannel(struct device * dev, void * data) +{ + struct subchannel *sch; + int irq = (unsigned long)data; + + sch = to_subchannel(dev); + return (sch->irq == irq); +} + struct subchannel * get_subchannel_by_schid(int irq) { - struct subchannel *sch; - struct list_head *entry; struct device *dev; - if (!get_bus(&css_bus_type)) - return NULL; - down_read(&css_bus_type.subsys.rwsem); - sch = NULL; - list_for_each(entry, &css_bus_type.devices.list) { - dev = get_device(container_of(entry, - struct device, bus_list)); - if (!dev) - continue; - sch = to_subchannel(dev); - if (sch->irq == irq) - break; - put_device(dev); - sch = NULL; - } - up_read(&css_bus_type.subsys.rwsem); - put_bus(&css_bus_type); + dev = bus_find_device(&css_bus_type, NULL, + (void *)(unsigned long)irq, check_subchannel); - return sch; + return dev ? to_subchannel(dev) : NULL; } + static inline int css_get_subchannel_status(struct subchannel *sch, int schid) { diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 809e110..14c76f5 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -514,36 +514,39 @@ ccw_device_register(struct ccw_device *cdev) return ret; } +struct match_data { + unsigned int devno; + struct ccw_device * sibling; +}; + +static int +match_devno(struct device * dev, void * data) +{ + struct match_data * d = (struct match_data *)data; + struct ccw_device * cdev; + + cdev = to_ccwdev(dev); + if ((cdev->private->state == DEV_STATE_DISCONNECTED) && + (cdev->private->devno == d->devno) && + (cdev != d->sibling)) { + cdev->private->state = DEV_STATE_NOT_OPER; + return 1; + } + return 0; +} + static struct ccw_device * get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) { - struct ccw_device *cdev; - struct list_head *entry; struct device *dev; + struct match_data data = { + .devno = devno, + .sibling = sibling, + }; - if (!get_bus(&ccw_bus_type)) - return NULL; - down_read(&ccw_bus_type.subsys.rwsem); - cdev = NULL; - list_for_each(entry, &ccw_bus_type.devices.list) { - dev = get_device(container_of(entry, - struct device, bus_list)); - if (!dev) - continue; - cdev = to_ccwdev(dev); - if ((cdev->private->state == DEV_STATE_DISCONNECTED) && - (cdev->private->devno == devno) && - (cdev != sibling)) { - cdev->private->state = DEV_STATE_NOT_OPER; - break; - } - put_device(dev); - cdev = NULL; - } - up_read(&ccw_bus_type.subsys.rwsem); - put_bus(&ccw_bus_type); + dev = bus_find_device(&css_bus_type, NULL, &data, match_devno); - return cdev; + return dev ? to_ccwdev(dev) : NULL; } static void @@ -647,7 +650,7 @@ io_subchannel_register(void *data) cdev = (struct ccw_device *) data; sch = to_subchannel(cdev->dev.parent); - if (!list_empty(&sch->dev.children)) { + if (klist_node_attached(&cdev->dev.knode_parent)) { bus_rescan_devices(&ccw_bus_type); goto out; } @@ -1019,30 +1022,29 @@ ccw_device_probe_console(void) /* * get ccw_device matching the busid, but only if owned by cdrv */ +static int +__ccwdev_check_busid(struct device *dev, void *id) +{ + char *bus_id; + + bus_id = (char *)id; + + return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0); +} + + struct ccw_device * get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) { - struct device *d, *dev; + struct device *dev; struct device_driver *drv; drv = get_driver(&cdrv->driver); if (!drv) - return 0; - - down_read(&drv->bus->subsys.rwsem); - - dev = NULL; - list_for_each_entry(d, &drv->devices, driver_list) { - dev = get_device(d); + return NULL; - if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE)) - break; - else if (dev) { - put_device(dev); - dev = NULL; - } - } - up_read(&drv->bus->subsys.rwsem); + dev = driver_find_device(drv, NULL, (void *)bus_id, + __ccwdev_check_busid); put_driver(drv); return dev ? to_ccwdev(dev) : 0; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index bbe9f45..82194c4 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.98 $" +#define VERSION_QDIO_C "$Revision: 1.101 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); @@ -3342,7 +3342,7 @@ static int qdio_register_dbf_views(void) { qdio_dbf_setup=debug_register(QDIO_DBF_SETUP_NAME, - QDIO_DBF_SETUP_INDEX, + QDIO_DBF_SETUP_PAGES, QDIO_DBF_SETUP_NR_AREAS, QDIO_DBF_SETUP_LEN); if (!qdio_dbf_setup) @@ -3351,7 +3351,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_setup,QDIO_DBF_SETUP_LEVEL); qdio_dbf_sbal=debug_register(QDIO_DBF_SBAL_NAME, - QDIO_DBF_SBAL_INDEX, + QDIO_DBF_SBAL_PAGES, QDIO_DBF_SBAL_NR_AREAS, QDIO_DBF_SBAL_LEN); if (!qdio_dbf_sbal) @@ -3361,7 +3361,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_sbal,QDIO_DBF_SBAL_LEVEL); qdio_dbf_sense=debug_register(QDIO_DBF_SENSE_NAME, - QDIO_DBF_SENSE_INDEX, + QDIO_DBF_SENSE_PAGES, QDIO_DBF_SENSE_NR_AREAS, QDIO_DBF_SENSE_LEN); if (!qdio_dbf_sense) @@ -3371,7 +3371,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_sense,QDIO_DBF_SENSE_LEVEL); qdio_dbf_trace=debug_register(QDIO_DBF_TRACE_NAME, - QDIO_DBF_TRACE_INDEX, + QDIO_DBF_TRACE_PAGES, QDIO_DBF_TRACE_NR_AREAS, QDIO_DBF_TRACE_LEN); if (!qdio_dbf_trace) @@ -3382,7 +3382,7 @@ qdio_register_dbf_views(void) #ifdef CONFIG_QDIO_DEBUG qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME, - QDIO_DBF_SLSB_OUT_INDEX, + QDIO_DBF_SLSB_OUT_PAGES, QDIO_DBF_SLSB_OUT_NR_AREAS, QDIO_DBF_SLSB_OUT_LEN); if (!qdio_dbf_slsb_out) @@ -3391,7 +3391,7 @@ qdio_register_dbf_views(void) debug_set_level(qdio_dbf_slsb_out,QDIO_DBF_SLSB_OUT_LEVEL); qdio_dbf_slsb_in=debug_register(QDIO_DBF_SLSB_IN_NAME, - QDIO_DBF_SLSB_IN_INDEX, + QDIO_DBF_SLSB_IN_PAGES, QDIO_DBF_SLSB_IN_NR_AREAS, QDIO_DBF_SLSB_IN_LEN); if (!qdio_dbf_slsb_in) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index b6daada..6b8aa6a 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -3,7 +3,7 @@ #include <asm/page.h> -#define VERSION_CIO_QDIO_H "$Revision: 1.32 $" +#define VERSION_CIO_QDIO_H "$Revision: 1.33 $" #ifdef CONFIG_QDIO_DEBUG #define QDIO_VERBOSE_LEVEL 9 @@ -132,7 +132,7 @@ enum qdio_irq_states { #define QDIO_DBF_SETUP_NAME "qdio_setup" #define QDIO_DBF_SETUP_LEN 8 -#define QDIO_DBF_SETUP_INDEX 2 +#define QDIO_DBF_SETUP_PAGES 4 #define QDIO_DBF_SETUP_NR_AREAS 1 #ifdef CONFIG_QDIO_DEBUG #define QDIO_DBF_SETUP_LEVEL 6 @@ -142,7 +142,7 @@ enum qdio_irq_states { #define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */ #define QDIO_DBF_SBAL_LEN 256 -#define QDIO_DBF_SBAL_INDEX 2 +#define QDIO_DBF_SBAL_PAGES 4 #define QDIO_DBF_SBAL_NR_AREAS 2 #ifdef CONFIG_QDIO_DEBUG #define QDIO_DBF_SBAL_LEVEL 6 @@ -154,16 +154,16 @@ enum qdio_irq_states { #define QDIO_DBF_TRACE_LEN 8 #define QDIO_DBF_TRACE_NR_AREAS 2 #ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_TRACE_INDEX 4 +#define QDIO_DBF_TRACE_PAGES 16 #define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */ #else /* CONFIG_QDIO_DEBUG */ -#define QDIO_DBF_TRACE_INDEX 2 +#define QDIO_DBF_TRACE_PAGES 4 #define QDIO_DBF_TRACE_LEVEL 2 #endif /* CONFIG_QDIO_DEBUG */ #define QDIO_DBF_SENSE_NAME "qdio_sense" #define QDIO_DBF_SENSE_LEN 64 -#define QDIO_DBF_SENSE_INDEX 1 +#define QDIO_DBF_SENSE_PAGES 2 #define QDIO_DBF_SENSE_NR_AREAS 1 #ifdef CONFIG_QDIO_DEBUG #define QDIO_DBF_SENSE_LEVEL 6 @@ -176,13 +176,13 @@ enum qdio_irq_states { #define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out" #define QDIO_DBF_SLSB_OUT_LEN QDIO_MAX_BUFFERS_PER_Q -#define QDIO_DBF_SLSB_OUT_INDEX 8 +#define QDIO_DBF_SLSB_OUT_PAGES 256 #define QDIO_DBF_SLSB_OUT_NR_AREAS 1 #define QDIO_DBF_SLSB_OUT_LEVEL 6 #define QDIO_DBF_SLSB_IN_NAME "qdio_slsb_in" #define QDIO_DBF_SLSB_IN_LEN QDIO_MAX_BUFFERS_PER_Q -#define QDIO_DBF_SLSB_IN_INDEX 8 +#define QDIO_DBF_SLSB_IN_PAGES 256 #define QDIO_DBF_SLSB_IN_NR_AREAS 1 #define QDIO_DBF_SLSB_IN_LEVEL 6 #endif /* CONFIG_QDIO_DEBUG */ diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index a99927d5..60440db 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -146,8 +146,8 @@ claw_unregister_debug_facility(void) static int claw_register_debug_facility(void) { - claw_dbf_setup = debug_register("claw_setup", 1, 1, 8); - claw_dbf_trace = debug_register("claw_trace", 1, 2, 8); + claw_dbf_setup = debug_register("claw_setup", 2, 1, 8); + claw_dbf_trace = debug_register("claw_trace", 2, 2, 8); if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) { printk(KERN_WARNING "Not enough memory for debug facility.\n"); claw_unregister_debug_facility(); diff --git a/drivers/s390/net/ctcdbug.c b/drivers/s390/net/ctcdbug.c index 2c86bfa..0e2a8bb 100644 --- a/drivers/s390/net/ctcdbug.c +++ b/drivers/s390/net/ctcdbug.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.4 $) + * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.6 $) * * CTC / ESCON network driver - s390 dbf exploit. * @@ -9,7 +9,7 @@ * Author(s): Original Code written by * Peter Tiedemann (ptiedem@de.ibm.com) * - * $Revision: 1.4 $ $Date: 2004/08/04 10:11:59 $ + * $Revision: 1.6 $ $Date: 2005/05/11 08:10:17 $ * * 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 @@ -51,15 +51,15 @@ int ctc_register_dbf_views(void) { ctc_dbf_setup = debug_register(CTC_DBF_SETUP_NAME, - CTC_DBF_SETUP_INDEX, + CTC_DBF_SETUP_PAGES, CTC_DBF_SETUP_NR_AREAS, CTC_DBF_SETUP_LEN); ctc_dbf_data = debug_register(CTC_DBF_DATA_NAME, - CTC_DBF_DATA_INDEX, + CTC_DBF_DATA_PAGES, CTC_DBF_DATA_NR_AREAS, CTC_DBF_DATA_LEN); ctc_dbf_trace = debug_register(CTC_DBF_TRACE_NAME, - CTC_DBF_TRACE_INDEX, + CTC_DBF_TRACE_PAGES, CTC_DBF_TRACE_NR_AREAS, CTC_DBF_TRACE_LEN); diff --git a/drivers/s390/net/ctcdbug.h b/drivers/s390/net/ctcdbug.h index 7fe2ebd..7d6afa1 100644 --- a/drivers/s390/net/ctcdbug.h +++ b/drivers/s390/net/ctcdbug.h @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $) + * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.6 $) * * CTC / ESCON network driver - s390 dbf exploit. * @@ -9,7 +9,7 @@ * Author(s): Original Code written by * Peter Tiedemann (ptiedem@de.ibm.com) * - * $Revision: 1.5 $ $Date: 2005/02/27 19:46:44 $ + * $Revision: 1.6 $ $Date: 2005/05/11 08:10:17 $ * * 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 @@ -35,19 +35,19 @@ */ #define CTC_DBF_SETUP_NAME "ctc_setup" #define CTC_DBF_SETUP_LEN 16 -#define CTC_DBF_SETUP_INDEX 3 +#define CTC_DBF_SETUP_PAGES 8 #define CTC_DBF_SETUP_NR_AREAS 1 #define CTC_DBF_SETUP_LEVEL 3 #define CTC_DBF_DATA_NAME "ctc_data" #define CTC_DBF_DATA_LEN 128 -#define CTC_DBF_DATA_INDEX 3 +#define CTC_DBF_DATA_PAGES 8 #define CTC_DBF_DATA_NR_AREAS 1 #define CTC_DBF_DATA_LEVEL 3 #define CTC_DBF_TRACE_NAME "ctc_trace" #define CTC_DBF_TRACE_LEN 16 -#define CTC_DBF_TRACE_INDEX 2 +#define CTC_DBF_TRACE_PAGES 4 #define CTC_DBF_TRACE_NR_AREAS 2 #define CTC_DBF_TRACE_LEVEL 3 diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h index 1983302..0c4644d 100644 --- a/drivers/s390/net/iucv.h +++ b/drivers/s390/net/iucv.h @@ -37,19 +37,19 @@ */ #define IUCV_DBF_SETUP_NAME "iucv_setup" #define IUCV_DBF_SETUP_LEN 32 -#define IUCV_DBF_SETUP_INDEX 1 +#define IUCV_DBF_SETUP_PAGES 2 #define IUCV_DBF_SETUP_NR_AREAS 1 #define IUCV_DBF_SETUP_LEVEL 3 #define IUCV_DBF_DATA_NAME "iucv_data" #define IUCV_DBF_DATA_LEN 128 -#define IUCV_DBF_DATA_INDEX 1 +#define IUCV_DBF_DATA_PAGES 2 #define IUCV_DBF_DATA_NR_AREAS 1 #define IUCV_DBF_DATA_LEVEL 2 #define IUCV_DBF_TRACE_NAME "iucv_trace" #define IUCV_DBF_TRACE_LEN 16 -#define IUCV_DBF_TRACE_INDEX 2 +#define IUCV_DBF_TRACE_PAGES 4 #define IUCV_DBF_TRACE_NR_AREAS 1 #define IUCV_DBF_TRACE_LEVEL 3 diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index ab08624..46f34ba 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -11,7 +11,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Martin Schwidefsky <schwidefsky@de.ibm.com> * - * $Revision: 1.98 $ $Date: 2005/04/18 13:41:29 $ + * $Revision: 1.99 $ $Date: 2005/05/11 08:10:17 $ * * 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 @@ -59,7 +59,7 @@ /** * initialization string for output */ -#define VERSION_LCS_C "$Revision: 1.98 $" +#define VERSION_LCS_C "$Revision: 1.99 $" static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char debug_buffer[255]; @@ -93,8 +93,8 @@ lcs_unregister_debug_facility(void) static int lcs_register_debug_facility(void) { - lcs_dbf_setup = debug_register("lcs_setup", 1, 1, 8); - lcs_dbf_trace = debug_register("lcs_trace", 1, 2, 8); + lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8); + lcs_dbf_trace = debug_register("lcs_trace", 2, 2, 8); if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { PRINT_ERR("Not enough memory for debug facility.\n"); lcs_unregister_debug_facility(); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3fd4fb7..69425a7 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,5 +1,5 @@ /* - * $Id: netiucv.c,v 1.63 2004/07/27 13:36:05 mschwide Exp $ + * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $ * * IUCV network driver * @@ -30,7 +30,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: IUCV network driver $Revision: 1.63 $ + * RELEASE-TAG: IUCV network driver $Revision: 1.66 $ * */ @@ -391,15 +391,15 @@ static int iucv_register_dbf_views(void) { iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, - IUCV_DBF_SETUP_INDEX, + IUCV_DBF_SETUP_PAGES, IUCV_DBF_SETUP_NR_AREAS, IUCV_DBF_SETUP_LEN); iucv_dbf_data = debug_register(IUCV_DBF_DATA_NAME, - IUCV_DBF_DATA_INDEX, + IUCV_DBF_DATA_PAGES, IUCV_DBF_DATA_NR_AREAS, IUCV_DBF_DATA_LEN); iucv_dbf_trace = debug_register(IUCV_DBF_TRACE_NAME, - IUCV_DBF_TRACE_INDEX, + IUCV_DBF_TRACE_PAGES, IUCV_DBF_TRACE_NR_AREAS, IUCV_DBF_TRACE_LEN); @@ -2076,7 +2076,7 @@ DRIVER_ATTR(remove, 0200, NULL, remove_write); static void netiucv_banner(void) { - char vbuf[] = "$Revision: 1.63 $"; + char vbuf[] = "$Revision: 1.66 $"; char *version = vbuf; if ((version = strchr(version, ':'))) { diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index a755b57..008e0a5 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -42,44 +42,44 @@ */ #define QETH_DBF_SETUP_NAME "qeth_setup" #define QETH_DBF_SETUP_LEN 8 -#define QETH_DBF_SETUP_INDEX 3 +#define QETH_DBF_SETUP_PAGES 8 #define QETH_DBF_SETUP_NR_AREAS 1 #define QETH_DBF_SETUP_LEVEL 5 #define QETH_DBF_MISC_NAME "qeth_misc" #define QETH_DBF_MISC_LEN 128 -#define QETH_DBF_MISC_INDEX 1 +#define QETH_DBF_MISC_PAGES 2 #define QETH_DBF_MISC_NR_AREAS 1 #define QETH_DBF_MISC_LEVEL 2 #define QETH_DBF_DATA_NAME "qeth_data" #define QETH_DBF_DATA_LEN 96 -#define QETH_DBF_DATA_INDEX 3 +#define QETH_DBF_DATA_PAGES 8 #define QETH_DBF_DATA_NR_AREAS 1 #define QETH_DBF_DATA_LEVEL 2 #define QETH_DBF_CONTROL_NAME "qeth_control" #define QETH_DBF_CONTROL_LEN 256 -#define QETH_DBF_CONTROL_INDEX 3 +#define QETH_DBF_CONTROL_PAGES 8 #define QETH_DBF_CONTROL_NR_AREAS 2 #define QETH_DBF_CONTROL_LEVEL 5 #define QETH_DBF_TRACE_NAME "qeth_trace" #define QETH_DBF_TRACE_LEN 8 -#define QETH_DBF_TRACE_INDEX 2 +#define QETH_DBF_TRACE_PAGES 4 #define QETH_DBF_TRACE_NR_AREAS 2 #define QETH_DBF_TRACE_LEVEL 3 extern debug_info_t *qeth_dbf_trace; #define QETH_DBF_SENSE_NAME "qeth_sense" #define QETH_DBF_SENSE_LEN 64 -#define QETH_DBF_SENSE_INDEX 1 +#define QETH_DBF_SENSE_PAGES 2 #define QETH_DBF_SENSE_NR_AREAS 1 #define QETH_DBF_SENSE_LEVEL 2 #define QETH_DBF_QERR_NAME "qeth_qerr" #define QETH_DBF_QERR_LEN 8 -#define QETH_DBF_QERR_INDEX 1 +#define QETH_DBF_QERR_PAGES 2 #define QETH_DBF_QERR_NR_AREAS 2 #define QETH_DBF_QERR_LEVEL 2 diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 208127a..3cb88c7 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -7639,31 +7639,31 @@ static int qeth_register_dbf_views(void) { qeth_dbf_setup = debug_register(QETH_DBF_SETUP_NAME, - QETH_DBF_SETUP_INDEX, + QETH_DBF_SETUP_PAGES, QETH_DBF_SETUP_NR_AREAS, QETH_DBF_SETUP_LEN); qeth_dbf_misc = debug_register(QETH_DBF_MISC_NAME, - QETH_DBF_MISC_INDEX, + QETH_DBF_MISC_PAGES, QETH_DBF_MISC_NR_AREAS, QETH_DBF_MISC_LEN); qeth_dbf_data = debug_register(QETH_DBF_DATA_NAME, - QETH_DBF_DATA_INDEX, + QETH_DBF_DATA_PAGES, QETH_DBF_DATA_NR_AREAS, QETH_DBF_DATA_LEN); qeth_dbf_control = debug_register(QETH_DBF_CONTROL_NAME, - QETH_DBF_CONTROL_INDEX, + QETH_DBF_CONTROL_PAGES, QETH_DBF_CONTROL_NR_AREAS, QETH_DBF_CONTROL_LEN); qeth_dbf_sense = debug_register(QETH_DBF_SENSE_NAME, - QETH_DBF_SENSE_INDEX, + QETH_DBF_SENSE_PAGES, QETH_DBF_SENSE_NR_AREAS, QETH_DBF_SENSE_LEN); qeth_dbf_qerr = debug_register(QETH_DBF_QERR_NAME, - QETH_DBF_QERR_INDEX, + QETH_DBF_QERR_PAGES, QETH_DBF_QERR_NR_AREAS, QETH_DBF_QERR_LEN); qeth_dbf_trace = debug_register(QETH_DBF_TRACE_NAME, - QETH_DBF_TRACE_INDEX, + QETH_DBF_TRACE_PAGES, QETH_DBF_TRACE_NR_AREAS, QETH_DBF_TRACE_LEN); diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 1e3f7f3..d6469ba 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -138,7 +138,7 @@ static void __exit smsg_exit(void) { if (smsg_handle > 0) { - cpcmd("SET SMSG OFF", 0, 0); + cpcmd("SET SMSG OFF", NULL, 0, NULL); iucv_sever(smsg_pathid, 0); iucv_unregister_program(smsg_handle); driver_unregister(&smsg_driver); @@ -177,7 +177,7 @@ smsg_init(void) smsg_handle = 0; return -EIO; } - cpcmd("SET SMSG IUCV", 0, 0); + cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; } diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index ffa996c..5bb255e 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -31,14 +31,14 @@ extern void css_reiterate_subchannels(void); extern struct workqueue_struct *slow_path_wq; extern struct work_struct slow_path_work; -static void +static NORET_TYPE void s390_handle_damage(char *msg) { - printk(KERN_EMERG "%s\n", msg); #ifdef CONFIG_SMP smp_send_stop(); #endif disabled_wait((unsigned long) __builtin_return_address(0)); + for(;;); } /* @@ -122,40 +122,39 @@ repeat: return 0; } +struct mcck_struct { + int kill_task; + int channel_report; + int warning; + unsigned long long mcck_code; +}; + +static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); + /* - * machine check handler. + * Main machine check handler function. Will be called with interrupts enabled + * or disabled and machine checks enabled or disabled. */ void -s390_do_machine_check(void) +s390_handle_mcck(void) { - struct mci *mci; - - mci = (struct mci *) &S390_lowcore.mcck_interruption_code; + unsigned long flags; + struct mcck_struct mcck; - if (mci->sd) /* system damage */ - s390_handle_damage("received system damage machine check\n"); + /* + * Disable machine checks and get the current state of accumulated + * machine checks. Afterwards delete the old state and enable machine + * checks again. + */ + local_irq_save(flags); + local_mcck_disable(); + mcck = __get_cpu_var(cpu_mcck); + memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); + clear_thread_flag(TIF_MCCK_PENDING); + local_mcck_enable(); + local_irq_restore(flags); - if (mci->pd) /* instruction processing damage */ - s390_handle_damage("received instruction processing " - "damage machine check\n"); - - if (mci->se) /* storage error uncorrected */ - s390_handle_damage("received storage error uncorrected " - "machine check\n"); - - if (mci->sc) /* storage error corrected */ - printk(KERN_WARNING - "received storage error corrected machine check\n"); - - if (mci->ke) /* storage key-error uncorrected */ - s390_handle_damage("received storage key-error uncorrected " - "machine check\n"); - - if (mci->ds && mci->fa) /* storage degradation */ - s390_handle_damage("received storage degradation machine " - "check\n"); - - if (mci->cp) /* channel report word pending */ + if (mcck.channel_report) up(&m_sem); #ifdef CONFIG_MACHCHK_WARNING @@ -168,7 +167,7 @@ s390_do_machine_check(void) * On VM we only get one interrupt per virtally presented machinecheck. * Though one suffices, we may get one interrupt per (virtual) processor. */ - if (mci->w) { /* WARNING pending ? */ + if (mcck.warning) { /* WARNING pending ? */ static int mchchk_wng_posted = 0; /* * Use single machine clear, as we cannot handle smp right now @@ -178,6 +177,261 @@ s390_do_machine_check(void) kill_proc(1, SIGPWR, 1); } #endif + + if (mcck.kill_task) { + local_irq_enable(); + printk(KERN_EMERG "mcck: Terminating task because of machine " + "malfunction (code 0x%016llx).\n", mcck.mcck_code); + printk(KERN_EMERG "mcck: task: %s, pid: %d.\n", + current->comm, current->pid); + do_exit(SIGSEGV); + } +} + +/* + * returns 0 if all registers could be validated + * returns 1 otherwise + */ +static int +s390_revalidate_registers(struct mci *mci) +{ + int kill_task; + u64 tmpclock; + u64 zero; + void *fpt_save_area, *fpt_creg_save_area; + + kill_task = 0; + zero = 0; + /* General purpose registers */ + if (!mci->gr) + /* + * General purpose registers couldn't be restored and have + * unknown contents. Process needs to be terminated. + */ + kill_task = 1; + + /* Revalidate floating point registers */ + if (!mci->fp) + /* + * Floating point registers can't be restored and + * therefore the process needs to be terminated. + */ + kill_task = 1; + +#ifndef __s390x__ + asm volatile("ld 0,0(%0)\n" + "ld 2,8(%0)\n" + "ld 4,16(%0)\n" + "ld 6,24(%0)" + : : "a" (&S390_lowcore.floating_pt_save_area)); +#endif + + if (MACHINE_HAS_IEEE) { +#ifdef __s390x__ + fpt_save_area = &S390_lowcore.floating_pt_save_area; + fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; +#else + fpt_save_area = (void *) S390_lowcore.extended_save_area_addr; + fpt_creg_save_area = fpt_save_area+128; +#endif + /* Floating point control register */ + if (!mci->fc) { + /* + * Floating point control register can't be restored. + * Task will be terminated. + */ + asm volatile ("lfpc 0(%0)" : : "a" (&zero)); + kill_task = 1; + + } + else + asm volatile ( + "lfpc 0(%0)" + : : "a" (fpt_creg_save_area)); + + asm volatile("ld 0,0(%0)\n" + "ld 1,8(%0)\n" + "ld 2,16(%0)\n" + "ld 3,24(%0)\n" + "ld 4,32(%0)\n" + "ld 5,40(%0)\n" + "ld 6,48(%0)\n" + "ld 7,56(%0)\n" + "ld 8,64(%0)\n" + "ld 9,72(%0)\n" + "ld 10,80(%0)\n" + "ld 11,88(%0)\n" + "ld 12,96(%0)\n" + "ld 13,104(%0)\n" + "ld 14,112(%0)\n" + "ld 15,120(%0)\n" + : : "a" (fpt_save_area)); + } + + /* Revalidate access registers */ + asm volatile("lam 0,15,0(%0)" + : : "a" (&S390_lowcore.access_regs_save_area)); + if (!mci->ar) + /* + * Access registers have unknown contents. + * Terminating task. + */ + kill_task = 1; + + /* Revalidate control registers */ + if (!mci->cr) + /* + * Control registers have unknown contents. + * Can't recover and therefore stopping machine. + */ + s390_handle_damage("invalid control registers."); + else +#ifdef __s390x__ + asm volatile("lctlg 0,15,0(%0)" + : : "a" (&S390_lowcore.cregs_save_area)); +#else + asm volatile("lctl 0,15,0(%0)" + : : "a" (&S390_lowcore.cregs_save_area)); +#endif + + /* + * We don't even try to revalidate the TOD register, since we simply + * can't write something sensible into that register. + */ + +#ifdef __s390x__ + /* + * See if we can revalidate the TOD programmable register with its + * old contents (should be zero) otherwise set it to zero. + */ + if (!mci->pr) + asm volatile("sr 0,0\n" + "sckpf" + : : : "0", "cc"); + else + asm volatile( + "l 0,0(%0)\n" + "sckpf" + : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc"); +#endif + + /* Revalidate clock comparator register */ + asm volatile ("stck 0(%1)\n" + "sckc 0(%1)" + : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory"); + + /* Check if old PSW is valid */ + if (!mci->wp) + /* + * Can't tell if we come from user or kernel mode + * -> stopping machine. + */ + s390_handle_damage("old psw invalid."); + + if (!mci->ms || !mci->pm || !mci->ia) + kill_task = 1; + + return kill_task; +} + +/* + * machine check handler. + */ +void +s390_do_machine_check(struct pt_regs *regs) +{ + struct mci *mci; + struct mcck_struct *mcck; + int umode; + + mci = (struct mci *) &S390_lowcore.mcck_interruption_code; + mcck = &__get_cpu_var(cpu_mcck); + umode = user_mode(regs); + + if (mci->sd) + /* System damage -> stopping machine */ + s390_handle_damage("received system damage machine check."); + + if (mci->pd) { + if (mci->b) { + /* Processing backup -> verify if we can survive this */ + u64 z_mcic, o_mcic, t_mcic; +#ifdef __s390x__ + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | + 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 | + 1ULL<<16); +#else + z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 | + 1ULL<<29); + o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | + 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | + 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16); +#endif + t_mcic = *(u64 *)mci; + + if (((t_mcic & z_mcic) != 0) || + ((t_mcic & o_mcic) != o_mcic)) { + s390_handle_damage("processing backup machine " + "check with damage."); + } + if (!umode) + s390_handle_damage("processing backup machine " + "check in kernel mode."); + mcck->kill_task = 1; + mcck->mcck_code = *(unsigned long long *) mci; + } + else { + /* Processing damage -> stopping machine */ + s390_handle_damage("received instruction processing " + "damage machine check."); + } + } + if (s390_revalidate_registers(mci)) { + if (umode) { + /* + * Couldn't restore all register contents while in + * user mode -> mark task for termination. + */ + mcck->kill_task = 1; + mcck->mcck_code = *(unsigned long long *) mci; + set_thread_flag(TIF_MCCK_PENDING); + } + else + /* + * Couldn't restore all register contents while in + * kernel mode -> stopping machine. + */ + s390_handle_damage("unable to revalidate registers."); + } + + if (mci->se) + /* Storage error uncorrected */ + s390_handle_damage("received storage error uncorrected " + "machine check."); + + if (mci->ke) + /* Storage key-error uncorrected */ + s390_handle_damage("received storage key-error uncorrected " + "machine check."); + + if (mci->ds && mci->fa) + /* Storage degradation */ + s390_handle_damage("received storage degradation machine " + "check."); + + if (mci->cp) { + /* Channel report word pending */ + mcck->channel_report = 1; + set_thread_flag(TIF_MCCK_PENDING); + } + + if (mci->w) { + /* Warning pending */ + mcck->warning = 1; + set_thread_flag(TIF_MCCK_PENDING); + } } /* @@ -189,9 +443,8 @@ static int machine_check_init(void) { init_MUTEX_LOCKED(&m_sem); - ctl_clear_bit(14, 25); /* disable damage MCH */ - ctl_set_bit(14, 26); /* enable degradation MCH */ - ctl_set_bit(14, 27); /* enable system recovery MCH */ + ctl_clear_bit(14, 25); /* disable external damage MCH */ + ctl_set_bit(14, 27); /* enable system recovery MCH */ #ifdef CONFIG_MACHCHK_WARNING ctl_set_bit(14, 24); /* enable warning MCH */ #endif diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 7e26f0f..4eaa701 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -16,20 +16,45 @@ struct mci { __u32 sd : 1; /* 00 system damage */ __u32 pd : 1; /* 01 instruction-processing damage */ __u32 sr : 1; /* 02 system recovery */ - __u32 to_be_defined_1 : 4; /* 03-06 */ + __u32 to_be_defined_1 : 1; /* 03 */ + __u32 cd : 1; /* 04 timing-facility damage */ + __u32 ed : 1; /* 05 external damage */ + __u32 to_be_defined_2 : 1; /* 06 */ __u32 dg : 1; /* 07 degradation */ __u32 w : 1; /* 08 warning pending */ __u32 cp : 1; /* 09 channel-report pending */ - __u32 to_be_defined_2 : 6; /* 10-15 */ + __u32 sp : 1; /* 10 service-processor damage */ + __u32 ck : 1; /* 11 channel-subsystem damage */ + __u32 to_be_defined_3 : 2; /* 12-13 */ + __u32 b : 1; /* 14 backed up */ + __u32 to_be_defined_4 : 1; /* 15 */ __u32 se : 1; /* 16 storage error uncorrected */ __u32 sc : 1; /* 17 storage error corrected */ __u32 ke : 1; /* 18 storage-key error uncorrected */ __u32 ds : 1; /* 19 storage degradation */ - __u32 to_be_defined_3 : 4; /* 20-23 */ + __u32 wp : 1; /* 20 psw mwp validity */ + __u32 ms : 1; /* 21 psw mask and key validity */ + __u32 pm : 1; /* 22 psw program mask and cc validity */ + __u32 ia : 1; /* 23 psw instruction address validity */ __u32 fa : 1; /* 24 failing storage address validity */ - __u32 to_be_defined_4 : 7; /* 25-31 */ + __u32 to_be_defined_5 : 1; /* 25 */ + __u32 ec : 1; /* 26 external damage code validity */ + __u32 fp : 1; /* 27 floating point register validity */ + __u32 gr : 1; /* 28 general register validity */ + __u32 cr : 1; /* 29 control register validity */ + __u32 to_be_defined_6 : 1; /* 30 */ + __u32 st : 1; /* 31 storage logical validity */ __u32 ie : 1; /* 32 indirect storage error */ - __u32 to_be_defined_5 : 31; /* 33-63 */ + __u32 ar : 1; /* 33 access register validity */ + __u32 da : 1; /* 34 delayed access exception */ + __u32 to_be_defined_7 : 7; /* 35-41 */ + __u32 pr : 1; /* 42 tod programmable register validity */ + __u32 fc : 1; /* 43 fp control register validity */ + __u32 ap : 1; /* 44 ancillary report */ + __u32 to_be_defined_8 : 1; /* 45 */ + __u32 ct : 1; /* 46 cpu timer validity */ + __u32 cc : 1; /* 47 clock comparator validity */ + __u32 to_be_defined_9 : 16; /* 47-63 */ }; /* diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index a699c30..bbe346b 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -34,7 +34,6 @@ #define ADDR32 (0) -#include <linux/version.h> #include <linux/module.h> MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn"); @@ -1811,9 +1810,9 @@ static int adpt_system_info(void __user *buffer) memset(&si, 0, sizeof(si)); si.osType = OS_LINUX; - si.osMajorVersion = (u8) (LINUX_VERSION_CODE >> 16); - si.osMinorVersion = (u8) (LINUX_VERSION_CODE >> 8 & 0x0ff); - si.osRevision = (u8) (LINUX_VERSION_CODE & 0x0ff); + si.osMajorVersion = 0; + si.osMinorVersion = 0; + si.osRevision = 0; si.busType = SI_PCI_BUS; si.processorFamily = DPTI_sig.dsProcessorFamily; diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 9821783..489194a 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -20,15 +20,7 @@ #ifndef _DPT_H #define _DPT_H -#ifndef LINUX_VERSION_CODE -#include <linux/version.h> -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,00) -#define MAX_TO_IOP_MESSAGES (210) -#else #define MAX_TO_IOP_MESSAGES (255) -#endif #define MAX_FROM_IOP_MESSAGES (255) @@ -321,10 +313,6 @@ static int adpt_close(struct inode *inode, struct file *file); static void adpt_delay(int millisec); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) -static struct pci_dev* adpt_pci_find_device(uint vendor, struct pci_dev* from); -#endif - #if defined __ia64__ static void adpt_ia64_info(sysInfo_S* si); #endif diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index f7ddc9f..2094d48 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -223,7 +223,7 @@ static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb); static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb); static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb); static int int_tul_busfree(HCS * pCurHcb); -int int_tul_scsi_rst(HCS * pCurHcb); +static int int_tul_scsi_rst(HCS * pCurHcb); static int int_tul_bad_seq(HCS * pCurHcb); static int int_tul_resel(HCS * pCurHcb); static int tul_sync_done(HCS * pCurHcb); @@ -240,9 +240,8 @@ static int tul_se2_rd_all(WORD CurBase); static void tul_se2_update_all(WORD CurBase); /* setup default pattern */ static void tul_read_eeprom(WORD CurBase); - /* ---- EXTERNAL VARIABLES ---- */ -HCS tul_hcs[MAX_SUPPORTED_ADAPTERS]; /* ---- INTERNAL VARIABLES ---- */ +static HCS tul_hcs[MAX_SUPPORTED_ADAPTERS]; static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS]; /*NVRAM nvram, *nvramp = &nvram; */ @@ -381,7 +380,7 @@ void tul_se2_wait(void) ******************************************************************/ -void tul_se2_instr(WORD CurBase, UCHAR instr) +static void tul_se2_instr(WORD CurBase, UCHAR instr) { int i; UCHAR b; @@ -437,7 +436,7 @@ void tul_se2_ew_ds(WORD CurBase) Input :address of Serial E2PROM Output :value stored in Serial E2PROM *******************************************************************/ -USHORT tul_se2_rd(WORD CurBase, ULONG adr) +static USHORT tul_se2_rd(WORD CurBase, ULONG adr) { UCHAR instr, readByte; USHORT readWord; @@ -468,7 +467,7 @@ USHORT tul_se2_rd(WORD CurBase, ULONG adr) /****************************************************************** Input: new value in Serial E2PROM, address of Serial E2PROM *******************************************************************/ -void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord) +static void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord) { UCHAR readByte; UCHAR instr; @@ -584,8 +583,8 @@ void tul_read_eeprom(WORD CurBase) TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT); } /* read_eeprom */ -int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt, - BYTE bBus, BYTE bDevice) +static int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt, + BYTE bBus, BYTE bDevice) { int i, j; @@ -616,7 +615,7 @@ int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt, return 1; } -void init_i91uAdapter_table(void) +static void init_i91uAdapter_table(void) { int i; @@ -630,7 +629,7 @@ void init_i91uAdapter_table(void) return; } -void tul_stop_bm(HCS * pCurHcb) +static void tul_stop_bm(HCS * pCurHcb) { if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */ @@ -642,7 +641,7 @@ void tul_stop_bm(HCS * pCurHcb) } /***************************************************************************/ -void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx) +static void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx) { pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE; /* Supply base address */ pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */ @@ -651,7 +650,7 @@ void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx) } /***************************************************************************/ -int tul_reset_scsi(HCS * pCurHcb, int seconds) +static int tul_reset_scsi(HCS * pCurHcb, int seconds) { TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS); @@ -670,7 +669,8 @@ int tul_reset_scsi(HCS * pCurHcb, int seconds) } /***************************************************************************/ -int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds) +static int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, + BYTE * pbBiosAdr, int seconds) { int i; BYTE *pwFlags; @@ -788,7 +788,7 @@ int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int } /***************************************************************************/ -SCB *tul_alloc_scb(HCS * hcsp) +static SCB *tul_alloc_scb(HCS * hcsp) { SCB *pTmpScb; ULONG flags; @@ -807,7 +807,7 @@ SCB *tul_alloc_scb(HCS * hcsp) } /***************************************************************************/ -void tul_release_scb(HCS * hcsp, SCB * scbp) +static void tul_release_scb(HCS * hcsp, SCB * scbp) { ULONG flags; @@ -829,7 +829,7 @@ void tul_release_scb(HCS * hcsp, SCB * scbp) } /***************************************************************************/ -void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp) +static void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp) { #if DEBUG_QUEUE @@ -847,7 +847,7 @@ void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp) } /***************************************************************************/ -void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp) +static void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp) { #if DEBUG_QUEUE @@ -863,7 +863,7 @@ void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp) } /***************************************************************************/ -SCB *tul_find_first_pend_scb(HCS * pCurHcb) +static SCB *tul_find_first_pend_scb(HCS * pCurHcb) { SCB *pFirstPend; @@ -894,24 +894,7 @@ SCB *tul_find_first_pend_scb(HCS * pCurHcb) return (pFirstPend); } /***************************************************************************/ -SCB *tul_pop_pend_scb(HCS * pCurHcb) -{ - SCB *pTmpScb; - - if ((pTmpScb = pCurHcb->HCS_FirstPend) != NULL) { - if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL) - pCurHcb->HCS_LastPend = NULL; - pTmpScb->SCB_NxtScb = NULL; - } -#if DEBUG_QUEUE - printk("Pop pend SCB %lx; ", (ULONG) pTmpScb); -#endif - return (pTmpScb); -} - - -/***************************************************************************/ -void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb) +static void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb) { SCB *pTmpScb, *pPrevScb; @@ -939,7 +922,7 @@ void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb) return; } /***************************************************************************/ -void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp) +static void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp) { #if DEBUG_QUEUE @@ -961,7 +944,7 @@ void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp) } /***************************************************************************/ -SCB *tul_pop_busy_scb(HCS * pCurHcb) +static SCB *tul_pop_busy_scb(HCS * pCurHcb) { SCB *pTmpScb; @@ -982,7 +965,7 @@ SCB *tul_pop_busy_scb(HCS * pCurHcb) } /***************************************************************************/ -void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb) +static void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb) { SCB *pTmpScb, *pPrevScb; @@ -1037,7 +1020,7 @@ SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun) } /***************************************************************************/ -void tul_append_done_scb(HCS * pCurHcb, SCB * scbp) +static void tul_append_done_scb(HCS * pCurHcb, SCB * scbp) { #if DEBUG_QUEUE @@ -1073,7 +1056,7 @@ SCB *tul_find_done_scb(HCS * pCurHcb) } /***************************************************************************/ -int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp) +static int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp) { ULONG flags; SCB *pTmpScb, *pPrevScb; @@ -1163,7 +1146,7 @@ int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp) } /***************************************************************************/ -int tul_bad_seq(HCS * pCurHcb) +static int tul_bad_seq(HCS * pCurHcb) { SCB *pCurScb; @@ -1182,9 +1165,11 @@ int tul_bad_seq(HCS * pCurHcb) return (tul_post_scsi_rst(pCurHcb)); } +#if 0 + /************************************************************************/ -int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb, - unsigned int target, unsigned int ResetFlags) +static int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb, + unsigned int target, unsigned int ResetFlags) { ULONG flags; SCB *pScb; @@ -1255,7 +1240,7 @@ int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb, return SCSI_RESET_PENDING; } -int tul_reset_scsi_bus(HCS * pCurHcb) +static int tul_reset_scsi_bus(HCS * pCurHcb) { ULONG flags; @@ -1284,8 +1269,10 @@ int tul_reset_scsi_bus(HCS * pCurHcb) return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET); } +#endif /* 0 */ + /************************************************************************/ -void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb) +static void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb) { ULONG flags; @@ -1318,7 +1305,7 @@ void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb) } /***************************************************************************/ -int tul_isr(HCS * pCurHcb) +static int tul_isr(HCS * pCurHcb) { /* Enter critical section */ @@ -2108,7 +2095,7 @@ int int_tul_busfree(HCS * pCurHcb) /***************************************************************************/ /* scsi bus reset */ -int int_tul_scsi_rst(HCS * pCurHcb) +static int int_tul_scsi_rst(HCS * pCurHcb) { SCB *pCurScb; int i; @@ -2214,7 +2201,7 @@ int int_tul_resel(HCS * pCurHcb) /***************************************************************************/ -int int_tul_bad_seq(HCS * pCurHcb) +static int int_tul_bad_seq(HCS * pCurHcb) { /* target wrong phase */ SCB *pCurScb; int i; diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h index df3ed7c..3efb118 100644 --- a/drivers/scsi/initio.h +++ b/drivers/scsi/initio.h @@ -719,21 +719,3 @@ typedef struct _HCSinfo { #define SCSI_RESET_HOST_RESET 0x200 #define SCSI_RESET_ACTION 0xff -extern void init_i91uAdapter_table(void); -extern int Addi91u_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE); -extern int tul_ReturnNumberOfAdapters(void); -extern void get_tulipPCIConfig(HCS * pHCB, int iChannel_index); -extern int init_tulip(HCS * pHCB, SCB * pSCB, int tul_num_scb, BYTE * pbBiosAdr, int reset_time); -extern SCB *tul_alloc_scb(HCS * pHCB); -extern int tul_abort_srb(HCS * pHCB, struct scsi_cmnd * pSRB); -extern void tul_exec_scb(HCS * pHCB, SCB * pSCB); -extern void tul_release_scb(HCS * pHCB, SCB * pSCB); -extern void tul_stop_bm(HCS * pHCB); -extern int tul_reset_scsi(HCS * pCurHcb, int seconds); -extern int tul_isr(HCS * pHCB); -extern int tul_reset(HCS * pHCB, struct scsi_cmnd * pSRB, unsigned char target); -extern int tul_reset_scsi_bus(HCS * pCurHcb); -extern int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb, - unsigned int target, unsigned int ResetFlags); - /* ---- EXTERNAL VARIABLES ---- */ -extern HCS tul_hcs[]; diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index db92a0c..feb8e73 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -992,18 +992,17 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value) /* * This routine sends a break character out the serial port. */ -static void send_break( struct m68k_serial * info, int duration) +static void send_break(struct m68k_serial * info, unsigned int duration) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (!info->port) return; - set_current_state(TASK_INTERRUPTIBLE); save_flags(flags); cli(); #ifdef USE_INTS uart->utx.w |= UTX_SEND_BREAK; - schedule_timeout(duration); + msleep_interruptible(duration); uart->utx.w &= ~UTX_SEND_BREAK; #endif restore_flags(flags); @@ -1033,14 +1032,14 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return retval; tty_wait_until_sent(tty, 0); if (!arg) - send_break(info, HZ/4); /* 1/4 second */ + send_break(info, 250); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); + send_break(info, arg ? arg*(100) : 250); return 0; case TIOCGSOFTCAR: error = put_user(C_CLOCAL(tty) ? 1 : 0, diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index f148022..b116122 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -1394,14 +1394,13 @@ static void end_break(ser_info_t *info) /* * This routine sends a break character out the serial port. */ -static void send_break(ser_info_t *info, int duration) +static void send_break(ser_info_t *info, unsigned int duration) { - set_current_state(TASK_INTERRUPTIBLE); #ifdef SERIAL_DEBUG_SEND_BREAK printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); #endif begin_break(info); - schedule_timeout(duration); + msleep_interruptible(duration); end_break(info); #ifdef SERIAL_DEBUG_SEND_BREAK printk("done jiffies=%lu\n", jiffies); @@ -1436,7 +1435,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file, if (signal_pending(current)) return -EINTR; if (!arg) { - send_break(info, HZ/4); /* 1/4 second */ + send_break(info, 250); /* 1/4 second */ if (signal_pending(current)) return -EINTR; } @@ -1448,7 +1447,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file, tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; - send_break(info, arg ? arg*(HZ/10) : HZ/4); + send_break(info, arg ? arg*100 : 250); if (signal_pending(current)) return -EINTR; return 0; diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h index 23dc0f7..798f1ef 100644 --- a/drivers/serial/icom.h +++ b/drivers/serial/icom.h @@ -286,5 +286,3 @@ struct lookup_int_table { u32 __iomem *global_int_mask; unsigned long processor_id; }; - -#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000) diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index a8314ae..a2a6433 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -67,7 +67,11 @@ static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS]; static struct mpsc_shared_regs mpsc_shared_regs; +static struct uart_driver mpsc_reg; +static void mpsc_start_rx(struct mpsc_port_info *pi); +static void mpsc_free_ring_mem(struct mpsc_port_info *pi); +static void mpsc_release_port(struct uart_port *port); /* ****************************************************************************** * @@ -546,7 +550,6 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi) { int rc = 0; - static void mpsc_free_ring_mem(struct mpsc_port_info *pi); pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n", pi->port.line); @@ -745,7 +748,6 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs) int rc = 0; u8 *bp; char flag = TTY_NORMAL; - static void mpsc_start_rx(struct mpsc_port_info *pi); pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); @@ -1178,7 +1180,6 @@ static void mpsc_shutdown(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - static void mpsc_release_port(struct uart_port *port); pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line); @@ -1448,7 +1449,6 @@ mpsc_console_setup(struct console *co, char *options) return uart_set_options(&pi->port, co, baud, parity, bits, flow); } -extern struct uart_driver mpsc_reg; static struct console mpsc_console = { .name = MPSC_DEV_NAME, .write = mpsc_console_write, diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 5c4231a..8e65206 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1071,7 +1071,7 @@ static void __init sunzilog_alloc_tables(void) */ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) { - unsigned long mapped_addr; + void __iomem *mapped_addr; unsigned int sun4u_ino; struct sbus_bus *sbus = NULL; struct sbus_dev *sdev = NULL; @@ -1111,9 +1111,9 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) apply_fhc_ranges(central_bus->child, &zsregs[0], 1); apply_central_ranges(central_bus, &zsregs[0], 1); - mapped_addr = - (((u64)zsregs[0].which_io)<<32UL) | - ((u64)zsregs[0].phys_addr); + mapped_addr = (void __iomem *) + ((((u64)zsregs[0].which_io)<<32UL) | + ((u64)zsregs[0].phys_addr)); } if (zilog_irq == -1) { diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index d5863b8..f2c9fa4 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -329,10 +329,8 @@ static IXJ *ixj_alloc() static void ixj_fsk_free(IXJ *j) { - if(j->fskdata != NULL) { - kfree(j->fskdata); - j->fskdata = NULL; - } + kfree(j->fskdata); + j->fskdata = NULL; } static void ixj_fsk_alloc(IXJ *j) @@ -3867,13 +3865,11 @@ static int set_rec_codec(IXJ *j, int rate) j->rec_mode = 7; break; default: + kfree(j->read_buffer); j->rec_frame_size = 0; j->rec_mode = -1; - if (j->read_buffer) { - kfree(j->read_buffer); - j->read_buffer = NULL; - j->read_buffer_size = 0; - } + j->read_buffer = NULL; + j->read_buffer_size = 0; retval = 1; break; } @@ -3991,14 +3987,12 @@ static int ixj_record_start(IXJ *j) static void ixj_record_stop(IXJ *j) { - if(ixjdebug & 0x0002) + if (ixjdebug & 0x0002) printk("IXJ %d Stopping Record Codec %d at %ld\n", j->board, j->rec_codec, jiffies); - if (j->read_buffer) { - kfree(j->read_buffer); - j->read_buffer = NULL; - j->read_buffer_size = 0; - } + kfree(j->read_buffer); + j->read_buffer = NULL; + j->read_buffer_size = 0; if (j->rec_mode > -1) { ixj_WriteDSPCommand(0x5120, j); j->rec_mode = -1; @@ -4449,13 +4443,11 @@ static int set_play_codec(IXJ *j, int rate) j->play_mode = 5; break; default: + kfree(j->write_buffer); j->play_frame_size = 0; j->play_mode = -1; - if (j->write_buffer) { - kfree(j->write_buffer); - j->write_buffer = NULL; - j->write_buffer_size = 0; - } + j->write_buffer = NULL; + j->write_buffer_size = 0; retval = 1; break; } @@ -4578,14 +4570,12 @@ static int ixj_play_start(IXJ *j) static void ixj_play_stop(IXJ *j) { - if(ixjdebug & 0x0002) + if (ixjdebug & 0x0002) printk("IXJ %d Stopping Play Codec %d at %ld\n", j->board, j->play_codec, jiffies); - if (j->write_buffer) { - kfree(j->write_buffer); - j->write_buffer = NULL; - j->write_buffer_size = 0; - } + kfree(j->write_buffer); + j->write_buffer = NULL; + j->write_buffer_size = 0; if (j->play_mode > -1) { ixj_WriteDSPCommand(0x5221, j); /* Stop playback and flush buffers. 8022 reference page 9-40 */ @@ -5810,9 +5800,7 @@ static void ixj_cpt_stop(IXJ *j) ixj_play_tone(j, 0); j->tone_state = j->tone_cadence_state = 0; if (j->cadence_t) { - if (j->cadence_t->ce) { - kfree(j->cadence_t->ce); - } + kfree(j->cadence_t->ce); kfree(j->cadence_t); j->cadence_t = NULL; } @@ -7497,10 +7485,8 @@ static void cleanup(void) printk(KERN_INFO "IXJ: Releasing XILINX address for /dev/phone%d\n", cnt); release_region(j->XILINXbase, 4); } - if (j->read_buffer) - kfree(j->read_buffer); - if (j->write_buffer) - kfree(j->write_buffer); + kfree(j->read_buffer); + kfree(j->write_buffer); if (j->dev) pnp_device_detach(j->dev); if (ixjdebug & 0x0002) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index d2d648e..a8d879a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2808,7 +2808,7 @@ static int hub_thread(void *__unused) do { hub_events(); wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); - try_to_freeze(PF_FREEZE); + try_to_freeze(); } while (!signal_pending(current)); pr_debug ("%s: khubd exiting\n", usbcore_name); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 037a7f1..a9be851 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -1554,8 +1554,7 @@ static int sleep_thread(struct fsg_dev *fsg) rc = wait_event_interruptible(fsg->thread_wqh, fsg->thread_wakeup_needed); fsg->thread_wakeup_needed = 0; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); return (rc ? -EINTR : 0); } diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 35c1ca6..77e7fc2 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -847,10 +847,8 @@ retry: wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DISCONNECTING, &us->flags), delay_use * HZ); - if (current->flags & PF_FREEZE) { - refrigerator(PF_FREEZE); + if (try_to_freeze()) goto retry; - } } /* If the device is still connected, perform the scanning */ diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index cacd88c..b6fe30c 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -111,15 +111,15 @@ static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, void au1100_nocursor(struct display *p, int mode, int xx, int yy){}; static struct fb_ops au1100fb_ops = { - owner: THIS_MODULE, - fb_get_fix: fbgen_get_fix, - fb_get_var: fbgen_get_var, - fb_set_var: fbgen_set_var, - fb_get_cmap: fbgen_get_cmap, - fb_set_cmap: fbgen_set_cmap, - fb_pan_display: fbgen_pan_display, - fb_ioctl: au1100fb_ioctl, - fb_mmap: au1100fb_mmap, + .owner = THIS_MODULE, + .fb_get_fix = fbgen_get_fix, + .fb_get_var = fbgen_get_var, + .fb_set_var = fbgen_set_var, + .fb_get_cmap = fbgen_get_cmap, + .fb_set_cmap = fbgen_set_cmap, + .fb_pan_display = fbgen_pan_display, + .fb_ioctl = au1100fb_ioctl, + .fb_mmap = au1100fb_mmap, }; static void au1100_detect(void) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index e4b91a4..cbff983 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -156,7 +156,6 @@ config FONT_6x11 config FONT_7x14 bool "console 7x14 font (not supported by all drivers)" if FONTS depends on FRAMEBUFFER_CONSOLE - default y if !SPARC32 && !SPARC64 && !FONTS help Console font with characters just a bit smaller than the default. If the standard 8x16 font is a little too big for you, say Y. @@ -197,8 +196,8 @@ config FONT_SUN12x22 standard font is unreadable for you, say Y, otherwise say N. config FONT_10x18 - bool "console 10x18 font (not supported by all drivers)" - depends on FONTS + bool "console 10x18 font (not supported by all drivers)" if FONTS + depends on FRAMEBUFFER_CONSOLE help This is a high resolution console font for machines with very big letters. It fits between the sun 12x22 and the normal 8x16 font. diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 277d733..7dfbf39 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -228,8 +228,6 @@ static ssize_t store_virtual(struct class_device *class_device, if (last - buf >= count) return -EINVAL; var.yres_virtual = simple_strtoul(last, &last, 0); - printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual, - var.yres_virtual); if ((err = activate(fb_info, &var))) return err; diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index 76fd3a5..a18dd02 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -197,10 +197,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { DBG(__FUNCTION__) hw->SEQ[0] = 0x00; - if (fwidth == 9) - hw->SEQ[1] = 0x00; - else - hw->SEQ[1] = 0x01; /* or 0x09 */ + hw->SEQ[1] = 0x01; /* or 0x09 */ hw->SEQ[2] = 0x0F; /* bitplanes */ hw->SEQ[3] = 0x00; hw->SEQ[4] = 0x0E; diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index f3069b0..9ed1a93 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -389,10 +389,11 @@ static int __init vesafb_probe(struct device *device) unsigned int temp_size = size_total; /* Find the largest power-of-two */ while (temp_size & (temp_size - 1)) - temp_size &= (temp_size - 1); - - /* Try and find a power of two to add */ - while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) { + temp_size &= (temp_size - 1); + + /* Try and find a power of two to add */ + while (temp_size > PAGE_SIZE && + mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) { temp_size >>= 1; } } diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index b460927..312cf32 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -646,7 +646,7 @@ static int w1_control(void *data) while (!control_needs_exit || have_to_wait) { have_to_wait = 0; - try_to_freeze(PF_FREEZE); + try_to_freeze(); msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) @@ -725,7 +725,7 @@ int w1_process(void *data) allow_signal(SIGTERM); while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { - try_to_freeze(PF_FREEZE); + try_to_freeze(); msleep_interruptible(w1_timeout * 1000); if (signal_pending(current)) @@ -734,6 +734,12 @@ config PROC_KCORE bool "/proc/kcore support" if !ARM depends on PROC_FS && MMU +config PROC_VMCORE + bool "/proc/vmcore support (EXPERIMENTAL)" + depends on PROC_FS && EMBEDDED && EXPERIMENTAL && CRASH_DUMP + help + Exports the dump image of crashed kernel in ELF format. + config SYSFS bool "sysfs file system support" if EMBEDDED default y diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c index 6fc88ae..7ac07d0 100644 --- a/fs/afs/kafsasyncd.c +++ b/fs/afs/kafsasyncd.c @@ -116,7 +116,7 @@ static int kafsasyncd(void *arg) remove_wait_queue(&kafsasyncd_sleepq, &myself); set_current_state(TASK_RUNNING); - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ afs_discard_my_signals(); diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c index 86e710d..65bc05a 100644 --- a/fs/afs/kafstimod.c +++ b/fs/afs/kafstimod.c @@ -91,7 +91,7 @@ static int kafstimod(void *arg) complete_and_exit(&kafstimod_dead, 0); } - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ afs_discard_my_signals(); @@ -409,13 +409,10 @@ out_dqlock: * for this sb+type at all. */ static void invalidate_dquots(struct super_block *sb, int type) { - struct dquot *dquot; - struct list_head *head; + struct dquot *dquot, *tmp; spin_lock(&dq_list_lock); - for (head = inuse_list.next; head != &inuse_list;) { - dquot = list_entry(head, struct dquot, dq_inuse); - head = head->next; + list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { if (dquot->dq_sb != sb) continue; if (dquot->dq_type != type) diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 1e6f2e2..5e7b439 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -167,7 +167,7 @@ loop: } wake_up(&journal->j_wait_done_commit); - if (current->flags & PF_FREEZE) { + if (freezing(current)) { /* * The simpler the better. Flushing journal isn't a * good idea, because that depends on threads that may @@ -175,7 +175,7 @@ loop: */ jbd_debug(1, "Now suspending kjournald\n"); spin_unlock(&journal->j_state_lock); - refrigerator(PF_FREEZE); + refrigerator(); spin_lock(&journal->j_state_lock); } else { /* diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 8cc6893..fc589dd 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -175,8 +175,64 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size) } } +/* Print the contents of a node. */ +static void +jffs_print_node(struct jffs_node *n) +{ + D(printk("jffs_node: 0x%p\n", n)); + D(printk("{\n")); + D(printk(" 0x%08x, /* version */\n", n->version)); + D(printk(" 0x%08x, /* data_offset */\n", n->data_offset)); + D(printk(" 0x%08x, /* data_size */\n", n->data_size)); + D(printk(" 0x%08x, /* removed_size */\n", n->removed_size)); + D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset)); + D(printk(" 0x%02x, /* name_size */\n", n->name_size)); + D(printk(" 0x%p, /* fm, fm->offset: %u */\n", + n->fm, (n->fm ? n->fm->offset : 0))); + D(printk(" 0x%p, /* version_prev */\n", n->version_prev)); + D(printk(" 0x%p, /* version_next */\n", n->version_next)); + D(printk(" 0x%p, /* range_prev */\n", n->range_prev)); + D(printk(" 0x%p, /* range_next */\n", n->range_next)); + D(printk("}\n")); +} + #endif +/* Print the contents of a raw inode. */ +static void +jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) +{ + D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino)); + D(printk("{\n")); + D(printk(" 0x%08x, /* magic */\n", raw_inode->magic)); + D(printk(" 0x%08x, /* ino */\n", raw_inode->ino)); + D(printk(" 0x%08x, /* pino */\n", raw_inode->pino)); + D(printk(" 0x%08x, /* version */\n", raw_inode->version)); + D(printk(" 0x%08x, /* mode */\n", raw_inode->mode)); + D(printk(" 0x%04x, /* uid */\n", raw_inode->uid)); + D(printk(" 0x%04x, /* gid */\n", raw_inode->gid)); + D(printk(" 0x%08x, /* atime */\n", raw_inode->atime)); + D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime)); + D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime)); + D(printk(" 0x%08x, /* offset */\n", raw_inode->offset)); + D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize)); + D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize)); + D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize)); + D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink)); + D(printk(" 0x%02x, /* spare */\n", + raw_inode->spare)); + D(printk(" %u, /* rename */\n", + raw_inode->rename)); + D(printk(" %u, /* deleted */\n", + raw_inode->deleted)); + D(printk(" 0x%02x, /* accurate */\n", + raw_inode->accurate)); + D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum)); + D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum)); + D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum)); + D(printk("}\n")); +} + #define flash_safe_acquire(arg) #define flash_safe_release(arg) @@ -2507,64 +2563,6 @@ jffs_update_file(struct jffs_file *f, struct jffs_node *node) return 0; } -/* Print the contents of a node. */ -void -jffs_print_node(struct jffs_node *n) -{ - D(printk("jffs_node: 0x%p\n", n)); - D(printk("{\n")); - D(printk(" 0x%08x, /* version */\n", n->version)); - D(printk(" 0x%08x, /* data_offset */\n", n->data_offset)); - D(printk(" 0x%08x, /* data_size */\n", n->data_size)); - D(printk(" 0x%08x, /* removed_size */\n", n->removed_size)); - D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset)); - D(printk(" 0x%02x, /* name_size */\n", n->name_size)); - D(printk(" 0x%p, /* fm, fm->offset: %u */\n", - n->fm, (n->fm ? n->fm->offset : 0))); - D(printk(" 0x%p, /* version_prev */\n", n->version_prev)); - D(printk(" 0x%p, /* version_next */\n", n->version_next)); - D(printk(" 0x%p, /* range_prev */\n", n->range_prev)); - D(printk(" 0x%p, /* range_next */\n", n->range_next)); - D(printk("}\n")); -} - - -/* Print the contents of a raw inode. */ -void -jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) -{ - D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino)); - D(printk("{\n")); - D(printk(" 0x%08x, /* magic */\n", raw_inode->magic)); - D(printk(" 0x%08x, /* ino */\n", raw_inode->ino)); - D(printk(" 0x%08x, /* pino */\n", raw_inode->pino)); - D(printk(" 0x%08x, /* version */\n", raw_inode->version)); - D(printk(" 0x%08x, /* mode */\n", raw_inode->mode)); - D(printk(" 0x%04x, /* uid */\n", raw_inode->uid)); - D(printk(" 0x%04x, /* gid */\n", raw_inode->gid)); - D(printk(" 0x%08x, /* atime */\n", raw_inode->atime)); - D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime)); - D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime)); - D(printk(" 0x%08x, /* offset */\n", raw_inode->offset)); - D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize)); - D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize)); - D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize)); - D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink)); - D(printk(" 0x%02x, /* spare */\n", - raw_inode->spare)); - D(printk(" %u, /* rename */\n", - raw_inode->rename)); - D(printk(" %u, /* deleted */\n", - raw_inode->deleted)); - D(printk(" 0x%02x, /* accurate */\n", - raw_inode->accurate)); - D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum)); - D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum)); - D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum)); - D(printk("}\n")); -} - - /* Print the contents of a file. */ #if 0 int diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h index 4ae97b1..5c7abe0 100644 --- a/fs/jffs/intrep.h +++ b/fs/jffs/intrep.h @@ -49,8 +49,6 @@ int jffs_garbage_collect_thread(void *c); void jffs_garbage_collect_trigger(struct jffs_control *c); /* For debugging purposes. */ -void jffs_print_node(struct jffs_node *n); -void jffs_print_raw_inode(struct jffs_raw_inode *raw_inode); #if 0 int jffs_print_file(struct jffs_file *f); #endif /* 0 */ diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c index 0cab8da..053e3a9 100644 --- a/fs/jffs/jffs_fm.c +++ b/fs/jffs/jffs_fm.c @@ -31,6 +31,60 @@ static void jffs_free_fm(struct jffs_fm *n); extern kmem_cache_t *fm_cache; extern kmem_cache_t *node_cache; +#if CONFIG_JFFS_FS_VERBOSE > 0 +void +jffs_print_fmcontrol(struct jffs_fmcontrol *fmc) +{ + D(printk("struct jffs_fmcontrol: 0x%p\n", fmc)); + D(printk("{\n")); + D(printk(" %u, /* flash_size */\n", fmc->flash_size)); + D(printk(" %u, /* used_size */\n", fmc->used_size)); + D(printk(" %u, /* dirty_size */\n", fmc->dirty_size)); + D(printk(" %u, /* free_size */\n", fmc->free_size)); + D(printk(" %u, /* sector_size */\n", fmc->sector_size)); + D(printk(" %u, /* min_free_size */\n", fmc->min_free_size)); + D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size)); + D(printk(" 0x%p, /* mtd */\n", fmc->mtd)); + D(printk(" 0x%p, /* head */ " + "(head->offset = 0x%08x)\n", + fmc->head, (fmc->head ? fmc->head->offset : 0))); + D(printk(" 0x%p, /* tail */ " + "(tail->offset + tail->size = 0x%08x)\n", + fmc->tail, + (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0))); + D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra)); + D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra)); + D(printk("}\n")); +} +#endif /* CONFIG_JFFS_FS_VERBOSE > 0 */ + +#if CONFIG_JFFS_FS_VERBOSE > 2 +static void +jffs_print_fm(struct jffs_fm *fm) +{ + D(printk("struct jffs_fm: 0x%p\n", fm)); + D(printk("{\n")); + D(printk(" 0x%08x, /* offset */\n", fm->offset)); + D(printk(" %u, /* size */\n", fm->size)); + D(printk(" 0x%p, /* prev */\n", fm->prev)); + D(printk(" 0x%p, /* next */\n", fm->next)); + D(printk(" 0x%p, /* nodes */\n", fm->nodes)); + D(printk("}\n")); +} +#endif /* CONFIG_JFFS_FS_VERBOSE > 2 */ + +#if 0 +void +jffs_print_node_ref(struct jffs_node_ref *ref) +{ + D(printk("struct jffs_node_ref: 0x%p\n", ref)); + D(printk("{\n")); + D(printk(" 0x%p, /* node */\n", ref->node)); + D(printk(" 0x%p, /* next */\n", ref->next)); + D(printk("}\n")); +} +#endif /* 0 */ + /* This function creates a new shiny flash memory control structure. */ struct jffs_fmcontrol * jffs_build_begin(struct jffs_control *c, int unit) @@ -742,54 +796,3 @@ int jffs_get_node_inuse(void) { return no_jffs_node; } - -void -jffs_print_fmcontrol(struct jffs_fmcontrol *fmc) -{ - D(printk("struct jffs_fmcontrol: 0x%p\n", fmc)); - D(printk("{\n")); - D(printk(" %u, /* flash_size */\n", fmc->flash_size)); - D(printk(" %u, /* used_size */\n", fmc->used_size)); - D(printk(" %u, /* dirty_size */\n", fmc->dirty_size)); - D(printk(" %u, /* free_size */\n", fmc->free_size)); - D(printk(" %u, /* sector_size */\n", fmc->sector_size)); - D(printk(" %u, /* min_free_size */\n", fmc->min_free_size)); - D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size)); - D(printk(" 0x%p, /* mtd */\n", fmc->mtd)); - D(printk(" 0x%p, /* head */ " - "(head->offset = 0x%08x)\n", - fmc->head, (fmc->head ? fmc->head->offset : 0))); - D(printk(" 0x%p, /* tail */ " - "(tail->offset + tail->size = 0x%08x)\n", - fmc->tail, - (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0))); - D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra)); - D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra)); - D(printk("}\n")); -} - -void -jffs_print_fm(struct jffs_fm *fm) -{ - D(printk("struct jffs_fm: 0x%p\n", fm)); - D(printk("{\n")); - D(printk(" 0x%08x, /* offset */\n", fm->offset)); - D(printk(" %u, /* size */\n", fm->size)); - D(printk(" 0x%p, /* prev */\n", fm->prev)); - D(printk(" 0x%p, /* next */\n", fm->next)); - D(printk(" 0x%p, /* nodes */\n", fm->nodes)); - D(printk("}\n")); -} - -#if 0 -void -jffs_print_node_ref(struct jffs_node_ref *ref) -{ - D(printk("struct jffs_node_ref: 0x%p\n", ref)); - D(printk("{\n")); - D(printk(" 0x%p, /* node */\n", ref->node)); - D(printk(" 0x%p, /* next */\n", ref->next)); - D(printk("}\n")); -} -#endif /* 0 */ - diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h index bc291c4..f64151e 100644 --- a/fs/jffs/jffs_fm.h +++ b/fs/jffs/jffs_fm.h @@ -139,8 +139,9 @@ int jffs_add_node(struct jffs_node *node); void jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm, __u32 size); +#if CONFIG_JFFS_FS_VERBOSE > 0 void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc); -void jffs_print_fm(struct jffs_fm *fm); +#endif #if 0 void jffs_print_node_ref(struct jffs_node_ref *ref); #endif /* 0 */ diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 1be6de2..638836b 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -92,7 +92,7 @@ static int jffs2_garbage_collect_thread(void *_c) schedule(); } - if (try_to_freeze(0)) + if (try_to_freeze()) continue; cond_resched(); diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 7c8387e..79d0762 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2359,9 +2359,9 @@ int jfsIOWait(void *arg) lbmStartIO(bp); spin_lock_irq(&log_redrive_lock); } - if (current->flags & PF_FREEZE) { + if (freezing(current)) { spin_unlock_irq(&log_redrive_lock); - refrigerator(PF_FREEZE); + refrigerator(); } else { add_wait_queue(&jfs_IO_thread_wait, &wq); set_current_state(TASK_INTERRUPTIBLE); diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 8cbaaff..121c981 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -2788,9 +2788,9 @@ int jfs_lazycommit(void *arg) /* In case a wakeup came while all threads were active */ jfs_commit_thread_waking = 0; - if (current->flags & PF_FREEZE) { + if (freezing(current)) { LAZY_UNLOCK(flags); - refrigerator(PF_FREEZE); + refrigerator(); } else { DECLARE_WAITQUEUE(wq, current); @@ -2987,9 +2987,9 @@ int jfs_sync(void *arg) /* Add anon_list2 back to anon_list */ list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list); - if (current->flags & PF_FREEZE) { + if (freezing(current)) { TXN_UNLOCK(); - refrigerator(PF_FREEZE); + refrigerator(); } else { DECLARE_WAITQUEUE(wq, current); @@ -183,6 +183,7 @@ struct file_operations simple_dir_operations = { .llseek = dcache_dir_lseek, .read = generic_read_dir, .readdir = dcache_readdir, + .fsync = simple_sync_file, }; struct inode_operations simple_dir_inode_operations = { diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index fd77ed1..14b3ce8 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -313,7 +313,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE); if (!signalled ()) { schedule_timeout(NLMCLNT_GRACE_WAIT); - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (!signalled ()) status = 0; } diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 2dc2d86..a9f7a8a 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -705,18 +705,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); return; } -#ifdef USE_OLD_SLOW_DIRECTORY_LISTING - for (;;) { - err = ncp_search_for_file_or_subdir(server, &seq, &entry.i); - if (err) { - DPRINTK("ncp_do_readdir: search failed, err=%d\n", err); - break; - } - entry.volume = entry.i.volNumber; - if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) - break; - } -#else /* We MUST NOT use server->buffer_size handshaked with server if we are using UDP, as for UDP server uses max. buffer size determined by MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). @@ -754,7 +742,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, } } while (more); vfree(buf); -#endif return; } diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index e4eb5ed..c755e18 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -845,46 +845,6 @@ out: return result; } -/* Search for everything */ -int ncp_search_for_file_or_subdir(struct ncp_server *server, - struct nw_search_sequence *seq, - struct nw_info_struct *target) -{ - int result; - - ncp_init_request(server); - ncp_add_byte(server, 3); /* subfunction */ - ncp_add_byte(server, server->name_space[seq->volNumber]); - ncp_add_byte(server, 0); /* data stream (???) */ - ncp_add_word(server, cpu_to_le16(0x8006)); /* Search attribs */ - ncp_add_dword(server, RIM_ALL); /* return info mask */ - ncp_add_mem(server, seq, 9); -#ifdef CONFIG_NCPFS_NFS_NS - if (server->name_space[seq->volNumber] == NW_NS_NFS) { - ncp_add_byte(server, 0); /* 0 byte pattern */ - } else -#endif - { - ncp_add_byte(server, 2); /* 2 byte pattern */ - ncp_add_byte(server, 0xff); /* following is a wildcard */ - ncp_add_byte(server, '*'); - } - - if ((result = ncp_request(server, 87)) != 0) - goto out; - memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq)); - ncp_extract_file_info(ncp_reply_data(server, 10), target); - - ncp_unlock_server(server); - - result = ncp_obtain_nfs_info(server, target); - return result; - -out: - ncp_unlock_server(server); - return result; -} - int ncp_search_for_fileset(struct ncp_server *server, struct nw_search_sequence *seq, int* more, diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 05ec2e9..9e4dc30 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -87,9 +87,6 @@ int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *, int ncp_initialize_search(struct ncp_server *, struct inode *, struct nw_search_sequence *target); -int ncp_search_for_file_or_subdir(struct ncp_server *server, - struct nw_search_sequence *seq, - struct nw_info_struct *target); int ncp_search_for_fileset(struct ncp_server *server, struct nw_search_sequence *seq, int* more, int* cnt, diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile index 4c83c17..66d5cc2 100644 --- a/fs/partitions/Makefile +++ b/fs/partitions/Makefile @@ -17,4 +17,3 @@ obj-$(CONFIG_SUN_PARTITION) += sun.o obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o obj-$(CONFIG_IBM_PARTITION) += ibm.o obj-$(CONFIG_EFI_PARTITION) += efi.o -obj-$(CONFIG_NEC98_PARTITION) += nec98.o msdos.o diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 2cab98a..77e178f 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -79,9 +79,6 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) = #ifdef CONFIG_LDM_PARTITION ldm_partition, /* this must come before msdos */ #endif -#ifdef CONFIG_NEC98_PARTITION - nec98_partition, /* must be come before `msdos_partition' */ -#endif #ifdef CONFIG_MSDOS_PARTITION msdos_partition, #endif diff --git a/fs/partitions/check.h b/fs/partitions/check.h index 43adcc6..17ae8ec 100644 --- a/fs/partitions/check.h +++ b/fs/partitions/check.h @@ -30,7 +30,3 @@ put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) extern int warn_no_part; -extern void parse_bsd(struct parsed_partitions *state, - struct block_device *bdev, u32 offset, u32 size, - int origin, char *flavour, int max_partitions); - diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 584a27b..9935d25 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -202,12 +202,12 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, #endif } -#if defined(CONFIG_BSD_DISKLABEL) || defined(CONFIG_NEC98_PARTITION) +#if defined(CONFIG_BSD_DISKLABEL) /* * Create devices for BSD partitions listed in a disklabel, under a * dos-like partition. See parse_extended() for more information. */ -void +static void parse_bsd(struct parsed_partitions *state, struct block_device *bdev, u32 offset, u32 size, int origin, char *flavour, int max_partitions) diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 738b9b6..7431d7b 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -11,4 +11,5 @@ proc-y += inode.o root.o base.o generic.o array.o \ kmsg.o proc_tty.o proc_misc.o proc-$(CONFIG_PROC_KCORE) += kcore.o +proc-$(CONFIG_PROC_VMCORE) += vmcore.o proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 94b570a..a345355 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -44,6 +44,7 @@ #include <linux/jiffies.h> #include <linux/sysrq.h> #include <linux/vmalloc.h> +#include <linux/crash_dump.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/io.h> @@ -618,6 +619,11 @@ void __init proc_misc_init(void) (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; } #endif +#ifdef CONFIG_PROC_VMCORE + proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL); + if (proc_vmcore) + proc_vmcore->proc_fops = &proc_vmcore_operations; +#endif #ifdef CONFIG_MAGIC_SYSRQ entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); if (entry) diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c new file mode 100644 index 0000000..3b2e7b69 --- /dev/null +++ b/fs/proc/vmcore.c @@ -0,0 +1,669 @@ +/* + * fs/proc/vmcore.c Interface for accessing the crash + * dump from the system's previous life. + * Heavily borrowed from fs/proc/kcore.c + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * Copyright (C) IBM Corporation, 2004. All rights reserved + * + */ + +#include <linux/config.h> +#include <linux/mm.h> +#include <linux/proc_fs.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/elf.h> +#include <linux/elfcore.h> +#include <linux/proc_fs.h> +#include <linux/highmem.h> +#include <linux/bootmem.h> +#include <linux/init.h> +#include <linux/crash_dump.h> +#include <linux/list.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +/* List representing chunks of contiguous memory areas and their offsets in + * vmcore file. + */ +static LIST_HEAD(vmcore_list); + +/* Stores the pointer to the buffer containing kernel elf core headers. */ +static char *elfcorebuf; +static size_t elfcorebuf_sz; + +/* Total size of vmcore file. */ +static u64 vmcore_size; + +struct proc_dir_entry *proc_vmcore = NULL; + +/* Reads a page from the oldmem device from given offset. */ +static ssize_t read_from_oldmem(char *buf, size_t count, + loff_t *ppos, int userbuf) +{ + unsigned long pfn, offset; + size_t nr_bytes; + ssize_t read = 0, tmp; + + if (!count) + return 0; + + offset = (unsigned long)(*ppos % PAGE_SIZE); + pfn = (unsigned long)(*ppos / PAGE_SIZE); + if (pfn > saved_max_pfn) + return -EINVAL; + + do { + if (count > (PAGE_SIZE - offset)) + nr_bytes = PAGE_SIZE - offset; + else + nr_bytes = count; + + tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf); + if (tmp < 0) + return tmp; + *ppos += nr_bytes; + count -= nr_bytes; + buf += nr_bytes; + read += nr_bytes; + ++pfn; + offset = 0; + } while (count); + + return read; +} + +/* Maps vmcore file offset to respective physical address in memroy. */ +static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list, + struct vmcore **m_ptr) +{ + struct vmcore *m; + u64 paddr; + + list_for_each_entry(m, vc_list, list) { + u64 start, end; + start = m->offset; + end = m->offset + m->size - 1; + if (offset >= start && offset <= end) { + paddr = m->paddr + offset - start; + *m_ptr = m; + return paddr; + } + } + *m_ptr = NULL; + return 0; +} + +/* Read from the ELF header and then the crash dump. On error, negative value is + * returned otherwise number of bytes read are returned. + */ +static ssize_t read_vmcore(struct file *file, char __user *buffer, + size_t buflen, loff_t *fpos) +{ + ssize_t acc = 0, tmp; + size_t tsz, nr_bytes; + u64 start; + struct vmcore *curr_m = NULL; + + if (buflen == 0 || *fpos >= vmcore_size) + return 0; + + /* trim buflen to not go beyond EOF */ + if (buflen > vmcore_size - *fpos) + buflen = vmcore_size - *fpos; + + /* Read ELF core header */ + if (*fpos < elfcorebuf_sz) { + tsz = elfcorebuf_sz - *fpos; + if (buflen < tsz) + tsz = buflen; + if (copy_to_user(buffer, elfcorebuf + *fpos, tsz)) + return -EFAULT; + buflen -= tsz; + *fpos += tsz; + buffer += tsz; + acc += tsz; + + /* leave now if filled buffer already */ + if (buflen == 0) + return acc; + } + + start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m); + if (!curr_m) + return -EINVAL; + if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) + tsz = buflen; + + /* Calculate left bytes in current memory segment. */ + nr_bytes = (curr_m->size - (start - curr_m->paddr)); + if (tsz > nr_bytes) + tsz = nr_bytes; + + while (buflen) { + tmp = read_from_oldmem(buffer, tsz, &start, 1); + if (tmp < 0) + return tmp; + buflen -= tsz; + *fpos += tsz; + buffer += tsz; + acc += tsz; + if (start >= (curr_m->paddr + curr_m->size)) { + if (curr_m->list.next == &vmcore_list) + return acc; /*EOF*/ + curr_m = list_entry(curr_m->list.next, + struct vmcore, list); + start = curr_m->paddr; + } + if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) + tsz = buflen; + /* Calculate left bytes in current memory segment. */ + nr_bytes = (curr_m->size - (start - curr_m->paddr)); + if (tsz > nr_bytes) + tsz = nr_bytes; + } + return acc; +} + +static int open_vmcore(struct inode *inode, struct file *filp) +{ + return 0; +} + +struct file_operations proc_vmcore_operations = { + .read = read_vmcore, + .open = open_vmcore, +}; + +static struct vmcore* __init get_new_element(void) +{ + struct vmcore *p; + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p) + memset(p, 0, sizeof(*p)); + return p; +} + +static u64 __init get_vmcore_size_elf64(char *elfptr) +{ + int i; + u64 size; + Elf64_Ehdr *ehdr_ptr; + Elf64_Phdr *phdr_ptr; + + ehdr_ptr = (Elf64_Ehdr *)elfptr; + phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); + size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr)); + for (i = 0; i < ehdr_ptr->e_phnum; i++) { + size += phdr_ptr->p_memsz; + phdr_ptr++; + } + return size; +} + +static u64 __init get_vmcore_size_elf32(char *elfptr) +{ + int i; + u64 size; + Elf32_Ehdr *ehdr_ptr; + Elf32_Phdr *phdr_ptr; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); + size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr)); + for (i = 0; i < ehdr_ptr->e_phnum; i++) { + size += phdr_ptr->p_memsz; + phdr_ptr++; + } + return size; +} + +/* Merges all the PT_NOTE headers into one. */ +static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, + struct list_head *vc_list) +{ + int i, nr_ptnote=0, rc=0; + char *tmp; + Elf64_Ehdr *ehdr_ptr; + Elf64_Phdr phdr, *phdr_ptr; + Elf64_Nhdr *nhdr_ptr; + u64 phdr_sz = 0, note_off; + + ehdr_ptr = (Elf64_Ehdr *)elfptr; + phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); + for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { + int j; + void *notes_section; + struct vmcore *new; + u64 offset, max_sz, sz, real_sz = 0; + if (phdr_ptr->p_type != PT_NOTE) + continue; + nr_ptnote++; + max_sz = phdr_ptr->p_memsz; + offset = phdr_ptr->p_offset; + notes_section = kmalloc(max_sz, GFP_KERNEL); + if (!notes_section) + return -ENOMEM; + rc = read_from_oldmem(notes_section, max_sz, &offset, 0); + if (rc < 0) { + kfree(notes_section); + return rc; + } + nhdr_ptr = notes_section; + for (j = 0; j < max_sz; j += sz) { + if (nhdr_ptr->n_namesz == 0) + break; + sz = sizeof(Elf64_Nhdr) + + ((nhdr_ptr->n_namesz + 3) & ~3) + + ((nhdr_ptr->n_descsz + 3) & ~3); + real_sz += sz; + nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz); + } + + /* Add this contiguous chunk of notes section to vmcore list.*/ + new = get_new_element(); + if (!new) { + kfree(notes_section); + return -ENOMEM; + } + new->paddr = phdr_ptr->p_offset; + new->size = real_sz; + list_add_tail(&new->list, vc_list); + phdr_sz += real_sz; + kfree(notes_section); + } + + /* Prepare merged PT_NOTE program header. */ + phdr.p_type = PT_NOTE; + phdr.p_flags = 0; + note_off = sizeof(Elf64_Ehdr) + + (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr); + phdr.p_offset = note_off; + phdr.p_vaddr = phdr.p_paddr = 0; + phdr.p_filesz = phdr.p_memsz = phdr_sz; + phdr.p_align = 0; + + /* Add merged PT_NOTE program header*/ + tmp = elfptr + sizeof(Elf64_Ehdr); + memcpy(tmp, &phdr, sizeof(phdr)); + tmp += sizeof(phdr); + + /* Remove unwanted PT_NOTE program headers. */ + i = (nr_ptnote - 1) * sizeof(Elf64_Phdr); + *elfsz = *elfsz - i; + memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr))); + + /* Modify e_phnum to reflect merged headers. */ + ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1; + + return 0; +} + +/* Merges all the PT_NOTE headers into one. */ +static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, + struct list_head *vc_list) +{ + int i, nr_ptnote=0, rc=0; + char *tmp; + Elf32_Ehdr *ehdr_ptr; + Elf32_Phdr phdr, *phdr_ptr; + Elf32_Nhdr *nhdr_ptr; + u64 phdr_sz = 0, note_off; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); + for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { + int j; + void *notes_section; + struct vmcore *new; + u64 offset, max_sz, sz, real_sz = 0; + if (phdr_ptr->p_type != PT_NOTE) + continue; + nr_ptnote++; + max_sz = phdr_ptr->p_memsz; + offset = phdr_ptr->p_offset; + notes_section = kmalloc(max_sz, GFP_KERNEL); + if (!notes_section) + return -ENOMEM; + rc = read_from_oldmem(notes_section, max_sz, &offset, 0); + if (rc < 0) { + kfree(notes_section); + return rc; + } + nhdr_ptr = notes_section; + for (j = 0; j < max_sz; j += sz) { + if (nhdr_ptr->n_namesz == 0) + break; + sz = sizeof(Elf32_Nhdr) + + ((nhdr_ptr->n_namesz + 3) & ~3) + + ((nhdr_ptr->n_descsz + 3) & ~3); + real_sz += sz; + nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz); + } + + /* Add this contiguous chunk of notes section to vmcore list.*/ + new = get_new_element(); + if (!new) { + kfree(notes_section); + return -ENOMEM; + } + new->paddr = phdr_ptr->p_offset; + new->size = real_sz; + list_add_tail(&new->list, vc_list); + phdr_sz += real_sz; + kfree(notes_section); + } + + /* Prepare merged PT_NOTE program header. */ + phdr.p_type = PT_NOTE; + phdr.p_flags = 0; + note_off = sizeof(Elf32_Ehdr) + + (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr); + phdr.p_offset = note_off; + phdr.p_vaddr = phdr.p_paddr = 0; + phdr.p_filesz = phdr.p_memsz = phdr_sz; + phdr.p_align = 0; + + /* Add merged PT_NOTE program header*/ + tmp = elfptr + sizeof(Elf32_Ehdr); + memcpy(tmp, &phdr, sizeof(phdr)); + tmp += sizeof(phdr); + + /* Remove unwanted PT_NOTE program headers. */ + i = (nr_ptnote - 1) * sizeof(Elf32_Phdr); + *elfsz = *elfsz - i; + memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr))); + + /* Modify e_phnum to reflect merged headers. */ + ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1; + + return 0; +} + +/* Add memory chunks represented by program headers to vmcore list. Also update + * the new offset fields of exported program headers. */ +static int __init process_ptload_program_headers_elf64(char *elfptr, + size_t elfsz, + struct list_head *vc_list) +{ + int i; + Elf64_Ehdr *ehdr_ptr; + Elf64_Phdr *phdr_ptr; + loff_t vmcore_off; + struct vmcore *new; + + ehdr_ptr = (Elf64_Ehdr *)elfptr; + phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */ + + /* First program header is PT_NOTE header. */ + vmcore_off = sizeof(Elf64_Ehdr) + + (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) + + phdr_ptr->p_memsz; /* Note sections */ + + for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { + if (phdr_ptr->p_type != PT_LOAD) + continue; + + /* Add this contiguous chunk of memory to vmcore list.*/ + new = get_new_element(); + if (!new) + return -ENOMEM; + new->paddr = phdr_ptr->p_offset; + new->size = phdr_ptr->p_memsz; + list_add_tail(&new->list, vc_list); + + /* Update the program header offset. */ + phdr_ptr->p_offset = vmcore_off; + vmcore_off = vmcore_off + phdr_ptr->p_memsz; + } + return 0; +} + +static int __init process_ptload_program_headers_elf32(char *elfptr, + size_t elfsz, + struct list_head *vc_list) +{ + int i; + Elf32_Ehdr *ehdr_ptr; + Elf32_Phdr *phdr_ptr; + loff_t vmcore_off; + struct vmcore *new; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */ + + /* First program header is PT_NOTE header. */ + vmcore_off = sizeof(Elf32_Ehdr) + + (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) + + phdr_ptr->p_memsz; /* Note sections */ + + for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { + if (phdr_ptr->p_type != PT_LOAD) + continue; + + /* Add this contiguous chunk of memory to vmcore list.*/ + new = get_new_element(); + if (!new) + return -ENOMEM; + new->paddr = phdr_ptr->p_offset; + new->size = phdr_ptr->p_memsz; + list_add_tail(&new->list, vc_list); + + /* Update the program header offset */ + phdr_ptr->p_offset = vmcore_off; + vmcore_off = vmcore_off + phdr_ptr->p_memsz; + } + return 0; +} + +/* Sets offset fields of vmcore elements. */ +static void __init set_vmcore_list_offsets_elf64(char *elfptr, + struct list_head *vc_list) +{ + loff_t vmcore_off; + Elf64_Ehdr *ehdr_ptr; + struct vmcore *m; + + ehdr_ptr = (Elf64_Ehdr *)elfptr; + + /* Skip Elf header and program headers. */ + vmcore_off = sizeof(Elf64_Ehdr) + + (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr); + + list_for_each_entry(m, vc_list, list) { + m->offset = vmcore_off; + vmcore_off += m->size; + } +} + +/* Sets offset fields of vmcore elements. */ +static void __init set_vmcore_list_offsets_elf32(char *elfptr, + struct list_head *vc_list) +{ + loff_t vmcore_off; + Elf32_Ehdr *ehdr_ptr; + struct vmcore *m; + + ehdr_ptr = (Elf32_Ehdr *)elfptr; + + /* Skip Elf header and program headers. */ + vmcore_off = sizeof(Elf32_Ehdr) + + (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr); + + list_for_each_entry(m, vc_list, list) { + m->offset = vmcore_off; + vmcore_off += m->size; + } +} + +static int __init parse_crash_elf64_headers(void) +{ + int rc=0; + Elf64_Ehdr ehdr; + u64 addr; + + addr = elfcorehdr_addr; + + /* Read Elf header */ + rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0); + if (rc < 0) + return rc; + + /* Do some basic Verification. */ + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || + (ehdr.e_type != ET_CORE) || + !elf_check_arch(&ehdr) || + ehdr.e_ident[EI_CLASS] != ELFCLASS64 || + ehdr.e_ident[EI_VERSION] != EV_CURRENT || + ehdr.e_version != EV_CURRENT || + ehdr.e_ehsize != sizeof(Elf64_Ehdr) || + ehdr.e_phentsize != sizeof(Elf64_Phdr) || + ehdr.e_phnum == 0) { + printk(KERN_WARNING "Warning: Core image elf header is not" + "sane\n"); + return -EINVAL; + } + + /* Read in all elf headers. */ + elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr); + elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL); + if (!elfcorebuf) + return -ENOMEM; + addr = elfcorehdr_addr; + rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0); + if (rc < 0) { + kfree(elfcorebuf); + return rc; + } + + /* Merge all PT_NOTE headers into one. */ + rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list); + if (rc) { + kfree(elfcorebuf); + return rc; + } + rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz, + &vmcore_list); + if (rc) { + kfree(elfcorebuf); + return rc; + } + set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list); + return 0; +} + +static int __init parse_crash_elf32_headers(void) +{ + int rc=0; + Elf32_Ehdr ehdr; + u64 addr; + + addr = elfcorehdr_addr; + + /* Read Elf header */ + rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0); + if (rc < 0) + return rc; + + /* Do some basic Verification. */ + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || + (ehdr.e_type != ET_CORE) || + !elf_check_arch(&ehdr) || + ehdr.e_ident[EI_CLASS] != ELFCLASS32|| + ehdr.e_ident[EI_VERSION] != EV_CURRENT || + ehdr.e_version != EV_CURRENT || + ehdr.e_ehsize != sizeof(Elf32_Ehdr) || + ehdr.e_phentsize != sizeof(Elf32_Phdr) || + ehdr.e_phnum == 0) { + printk(KERN_WARNING "Warning: Core image elf header is not" + "sane\n"); + return -EINVAL; + } + + /* Read in all elf headers. */ + elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr); + elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL); + if (!elfcorebuf) + return -ENOMEM; + addr = elfcorehdr_addr; + rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0); + if (rc < 0) { + kfree(elfcorebuf); + return rc; + } + + /* Merge all PT_NOTE headers into one. */ + rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list); + if (rc) { + kfree(elfcorebuf); + return rc; + } + rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz, + &vmcore_list); + if (rc) { + kfree(elfcorebuf); + return rc; + } + set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list); + return 0; +} + +static int __init parse_crash_elf_headers(void) +{ + unsigned char e_ident[EI_NIDENT]; + u64 addr; + int rc=0; + + addr = elfcorehdr_addr; + rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0); + if (rc < 0) + return rc; + if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { + printk(KERN_WARNING "Warning: Core image elf header" + " not found\n"); + return -EINVAL; + } + + if (e_ident[EI_CLASS] == ELFCLASS64) { + rc = parse_crash_elf64_headers(); + if (rc) + return rc; + + /* Determine vmcore size. */ + vmcore_size = get_vmcore_size_elf64(elfcorebuf); + } else if (e_ident[EI_CLASS] == ELFCLASS32) { + rc = parse_crash_elf32_headers(); + if (rc) + return rc; + + /* Determine vmcore size. */ + vmcore_size = get_vmcore_size_elf32(elfcorebuf); + } else { + printk(KERN_WARNING "Warning: Core image elf header is not" + " sane\n"); + return -EINVAL; + } + return 0; +} + +/* Init function for vmcore module. */ +static int __init vmcore_init(void) +{ + int rc = 0; + + /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/ + if (!(elfcorehdr_addr < ELFCORE_ADDR_MAX)) + return rc; + rc = parse_crash_elf_headers(); + if (rc) { + printk(KERN_WARNING "Kdump: vmcore not initialized\n"); + return rc; + } + + /* Initialize /proc/vmcore size if proc is already up. */ + if (proc_vmcore) + proc_vmcore->size = vmcore_size; + return 0; +} +module_init(vmcore_init) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 0d5817f..289d864 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -254,6 +254,7 @@ static int _get_block_create_0 (struct inode * inode, long block, char * p = NULL; int chars; int ret ; + int result ; int done = 0 ; unsigned long offset ; @@ -262,10 +263,13 @@ static int _get_block_create_0 (struct inode * inode, long block, (loff_t)block * inode->i_sb->s_blocksize + 1, TYPE_ANY, 3); research: - if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) { + result = search_for_position_by_key (inode->i_sb, &key, &path) ; + if (result != POSITION_FOUND) { pathrelse (&path); if (p) kunmap(bh_result->b_page) ; + if (result == IO_ERROR) + return -EIO; // We do not return -ENOENT if there is a hole but page is uptodate, because it means // That there is some MMAPED data associated with it that is yet to be written to disk. if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) { @@ -382,8 +386,9 @@ research: // update key to look for the next piece set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars); - if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) - // we read something from tail, even if now we got IO_ERROR + result = search_for_position_by_key (inode->i_sb, &key, &path); + if (result != POSITION_FOUND) + // i/o error most likely break; bh = get_last_bh (&path); ih = get_ih (&path); @@ -394,6 +399,10 @@ research: finished: pathrelse (&path); + + if (result == IO_ERROR) + return -EIO; + /* this buffer has valid data, but isn't valid for io. mapping it to * block #0 tells the rest of reiserfs it just has a tail in it */ diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index c60e694..df0cba2 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1771,9 +1771,9 @@ xfsbufd( INIT_LIST_HEAD(&tmp); do { - if (unlikely(current->flags & PF_FREEZE)) { + if (unlikely(freezing(current))) { xfsbufd_force_sleep = 1; - refrigerator(PF_FREEZE); + refrigerator(); } else { xfsbufd_force_sleep = 0; } diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 5fe9af3..f6dd7de 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -483,7 +483,7 @@ xfssyncd( set_current_state(TASK_INTERRUPTIBLE); timeleft = schedule_timeout(timeleft); /* swsusp */ - try_to_freeze(PF_FREEZE); + try_to_freeze(); if (vfsp->vfs_flag & VFS_UMOUNT) break; diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h index 5e56b47..3241cd6 100644 --- a/include/asm-arm/arch-ixp2000/io.h +++ b/include/asm-arm/arch-ixp2000/io.h @@ -17,16 +17,21 @@ #define IO_SPACE_LIMIT 0xffffffff #define __mem_pci(a) (a) -#define ___io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE)) /* - * The IXP2400 before revision B0 asserts byte lanes for PCI I/O + * The A? revisions of the IXP2000s assert byte lanes for PCI I/O * transactions the other way round (MEM transactions don't have this - * issue), so we need to override the standard functions. B0 and later - * have a bit that can be set to 1 to get the 'proper' behavior, but - * since that isn't available on the A? revisions we just keep doing - * things manually. + * issue), so if we want to support those models, we need to override + * the standard I/O functions. + * + * B0 and later have a bit that can be set to 1 to get the proper + * behavior for I/O transactions, which then allows us to use the + * standard I/O functions. This is what we do if the user does not + * explicitly ask for support for pre-B0. */ +#ifdef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO +#define ___io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE)) + #define alignb(addr) (void __iomem *)((unsigned long)(addr) ^ 3) #define alignw(addr) (void __iomem *)((unsigned long)(addr) ^ 2) @@ -119,6 +124,9 @@ #define ioport_map(port, nr) ___io(port) #define ioport_unmap(addr) +#else +#define __io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE)) +#endif #ifdef CONFIG_ARCH_IXDP2X01 diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index a1d9e18..5eb47d4 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -241,7 +241,7 @@ #define PCI_CONTROL_BE_DEI (1 << 21) /* Big Endian Data Enable In */ #define PCI_CONTROL_BE_BEO (1 << 20) /* Big Endian Byte Enable Out */ #define PCI_CONTROL_BE_BEI (1 << 19) /* Big Endian Byte Enable In */ -#define PCI_CONTROL_PNR (1 << 17) /* PCI Not Reset bit */ +#define PCI_CONTROL_IEE (1 << 17) /* I/O cycle Endian swap Enable */ #define IXP2000_PCI_RST_REL (1 << 2) #define CFG_RST_DIR (*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF) diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h index 5cf4fd6..047980a 100644 --- a/include/asm-arm/mach/time.h +++ b/include/asm-arm/mach/time.h @@ -39,8 +39,29 @@ struct sys_timer { void (*suspend)(void); void (*resume)(void); unsigned long (*offset)(void); + +#ifdef CONFIG_NO_IDLE_HZ + struct dyn_tick_timer *dyn_tick; +#endif +}; + +#ifdef CONFIG_NO_IDLE_HZ + +#define DYN_TICK_SKIPPING (1 << 2) +#define DYN_TICK_ENABLED (1 << 1) +#define DYN_TICK_SUITABLE (1 << 0) + +struct dyn_tick_timer { + unsigned int state; /* Current state */ + int (*enable)(void); /* Enables dynamic tick */ + int (*disable)(void); /* Disables dynamic tick */ + void (*reprogram)(unsigned long); /* Reprograms the timer */ + int (*handler)(int, void *, struct pt_regs *); }; +void timer_dyn_reprogram(void); +#endif + extern struct sys_timer *system_timer; extern void timer_tick(struct pt_regs *); diff --git a/include/asm-arm/signal.h b/include/asm-arm/signal.h index 46e69ae..760f6e65 100644 --- a/include/asm-arm/signal.h +++ b/include/asm-arm/signal.h @@ -114,6 +114,7 @@ typedef unsigned long sigset_t; #define SIGSTKSZ 8192 #ifdef __KERNEL__ +#define SA_TIMER 0x40000000 #define SA_IRQNOMASK 0x08000000 #endif diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index 39dd700..3d0d286 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -145,34 +145,12 @@ extern unsigned int user_debug; #define set_wmb(var, value) do { var = value; wmb(); } while (0) #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); -#ifdef CONFIG_SMP /* - * Define our own context switch locking. This allows us to enable - * interrupts over the context switch, otherwise we end up with high - * interrupt latency. The real problem area is switch_mm() which may - * do a full cache flush. + * switch_mm() may do a full cache flush over the context switch, + * so enable interrupts over the context switch to avoid high + * latency. */ -#define prepare_arch_switch(rq,next) \ -do { \ - spin_lock(&(next)->switch_lock); \ - spin_unlock_irq(&(rq)->lock); \ -} while (0) - -#define finish_arch_switch(rq,prev) \ - spin_unlock(&(prev)->switch_lock) - -#define task_running(rq,p) \ - ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) -#else -/* - * Our UP-case is more simple, but we assume knowledge of how - * spin_unlock_irq() and friends are implemented. This avoids - * us needlessly decrementing and incrementing the preempt count. - */ -#define prepare_arch_switch(rq,next) local_irq_enable() -#define finish_arch_switch(rq,prev) spin_unlock(&(rq)->lock) -#define task_running(rq,p) ((rq)->curr == (p)) -#endif +#define __ARCH_WANT_INTERRUPTS_ON_CTXSW /* * switch_to(prev, next) should switch from task `prev' to `next' diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 99cef06..b3bb326 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -73,7 +73,7 @@ } #define SECURITY_INIT \ - .security_initcall.init : { \ + .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__security_initcall_start) = .; \ *(.security_initcall.init) \ VMLINUX_SYMBOL(__security_initcall_end) = .; \ diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index a5810cf..6a1b188 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -5,6 +5,7 @@ #include <linux/pm.h> #include <asm/fixmap.h> #include <asm/apicdef.h> +#include <asm/processor.h> #include <asm/system.h> #define Dprintk(x...) @@ -16,8 +17,20 @@ #define APIC_VERBOSE 1 #define APIC_DEBUG 2 +extern int enable_local_apic; extern int apic_verbosity; +static inline void lapic_disable(void) +{ + enable_local_apic = -1; + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); +} + +static inline void lapic_enable(void) +{ + enable_local_apic = 1; +} + /* * Define the default level of output to be very little * This can be turned up by using apic=verbose for more @@ -87,7 +100,7 @@ extern void (*wait_timer_tick)(void); extern int get_maxlvt(void); extern void clear_local_APIC(void); extern void connect_bsp_APIC (void); -extern void disconnect_bsp_APIC (void); +extern void disconnect_bsp_APIC (int virt_wire_setup); extern void disable_local_APIC (void); extern void lapic_shutdown (void); extern int verify_local_APIC (void); diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h index c689554..0fed5e3 100644 --- a/include/asm-i386/apicdef.h +++ b/include/asm-i386/apicdef.h @@ -86,11 +86,12 @@ #define APIC_LVT_REMOTE_IRR (1<<14) #define APIC_INPUT_POLARITY (1<<13) #define APIC_SEND_PENDING (1<<12) +#define APIC_MODE_MASK 0x700 #define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) #define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) #define APIC_MODE_FIXED 0x0 #define APIC_MODE_NMI 0x4 -#define APIC_MODE_EXINT 0x7 +#define APIC_MODE_EXTINT 0x7 #define APIC_LVT1 0x360 #define APIC_LVTERR 0x370 #define APIC_TMICT 0x380 diff --git a/include/asm-i386/cpu.h b/include/asm-i386/cpu.h index 002740b..e7252c2 100644 --- a/include/asm-i386/cpu.h +++ b/include/asm-i386/cpu.h @@ -5,6 +5,7 @@ #include <linux/cpu.h> #include <linux/topology.h> #include <linux/nodemask.h> +#include <linux/percpu.h> #include <asm/node.h> @@ -16,4 +17,5 @@ extern int arch_register_cpu(int num); extern void arch_unregister_cpu(int); #endif +DECLARE_PER_CPU(int, cpu_state); #endif /* _ASM_I386_CPU_H_ */ diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h index 1df42bf..0fd3313 100644 --- a/include/asm-i386/highmem.h +++ b/include/asm-i386/highmem.h @@ -70,6 +70,7 @@ void *kmap(struct page *page); void kunmap(struct page *page); void *kmap_atomic(struct page *page, enum km_type type); void kunmap_atomic(void *kvaddr, enum km_type type); +void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); struct page *kmap_atomic_to_page(void *ptr); #define flush_cache_kmaps() do { } while (0) diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h index 05b9e61..270f198 100644 --- a/include/asm-i386/irq.h +++ b/include/asm-i386/irq.h @@ -29,13 +29,19 @@ extern void release_vm86_irqs(struct task_struct *); #ifdef CONFIG_4KSTACKS extern void irq_ctx_init(int cpu); + extern void irq_ctx_exit(int cpu); # define __ARCH_HAS_DO_SOFTIRQ #else # define irq_ctx_init(cpu) do { } while (0) +# define irq_ctx_exit(cpu) do { } while (0) #endif #ifdef CONFIG_IRQBALANCE extern int irqbalance_disable(char *str); #endif +#ifdef CONFIG_HOTPLUG_CPU +extern void fixup_irqs(cpumask_t map); +#endif + #endif /* _ASM_IRQ_H */ diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h index de6498b..b3f8d5f 100644 --- a/include/asm-i386/kdebug.h +++ b/include/asm-i386/kdebug.h @@ -18,7 +18,7 @@ struct die_args { }; /* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_kernel - then free. + If you really want to do it first unregister - then synchronize_sched - then free. */ int register_die_notifier(struct notifier_block *nb); extern struct notifier_block *i386die_chain; diff --git a/include/asm-i386/kexec.h b/include/asm-i386/kexec.h new file mode 100644 index 0000000..6ed2a03 --- /dev/null +++ b/include/asm-i386/kexec.h @@ -0,0 +1,33 @@ +#ifndef _I386_KEXEC_H +#define _I386_KEXEC_H + +#include <asm/fixmap.h> + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct + * calculation for the amount of memory directly mappable into the + * kernel memory space. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE + +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_386 + +#define MAX_NOTE_BYTES 1024 +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; + +extern note_buf_t crash_notes[]; + +#endif /* _I386_KEXEC_H */ diff --git a/include/asm-i386/mach-default/mach_ipi.h b/include/asm-i386/mach-default/mach_ipi.h index 6f2b17a..cc756a6 100644 --- a/include/asm-i386/mach-default/mach_ipi.h +++ b/include/asm-i386/mach-default/mach_ipi.h @@ -4,11 +4,34 @@ void send_IPI_mask_bitmask(cpumask_t mask, int vector); void __send_IPI_shortcut(unsigned int shortcut, int vector); +extern int no_broadcast; + static inline void send_IPI_mask(cpumask_t mask, int vector) { send_IPI_mask_bitmask(mask, vector); } +static inline void __local_send_IPI_allbutself(int vector) +{ + if (no_broadcast) { + cpumask_t mask = cpu_online_map; + int this_cpu = get_cpu(); + + cpu_clear(this_cpu, mask); + send_IPI_mask(mask, vector); + put_cpu(); + } else + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); +} + +static inline void __local_send_IPI_all(int vector) +{ + if (no_broadcast) + send_IPI_mask(cpu_online_map, vector); + else + __send_IPI_shortcut(APIC_DEST_ALLINC, vector); +} + static inline void send_IPI_allbutself(int vector) { /* @@ -18,13 +41,13 @@ static inline void send_IPI_allbutself(int vector) if (!(num_online_cpus() > 1)) return; - __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); + __local_send_IPI_allbutself(vector); return; } static inline void send_IPI_all(int vector) { - __send_IPI_shortcut(APIC_DEST_ALLINC, vector); + __local_send_IPI_all(vector); } #endif /* __ASM_MACH_IPI_H */ diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index dea8f8e..8d93f73 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -126,9 +126,12 @@ extern int page_is_ram(unsigned long pagenr); #ifdef __ASSEMBLY__ #define __PAGE_OFFSET (0xC0000000) +#define __PHYSICAL_START CONFIG_PHYSICAL_START #else #define __PAGE_OFFSET (0xC0000000UL) +#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START) #endif +#define __KERNEL_START (__PAGE_OFFSET + __PHYSICAL_START) #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index c76c50e..6f0f93d 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -691,5 +691,7 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c); #define cache_line_size() (boot_cpu_data.x86_cache_alignment) extern unsigned long boot_option_idle_override; +extern void enable_sep_cpu(void); +extern int sysenter_setup(void); #endif /* __ASM_I386_PROCESSOR_H */ diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 55ef31f..edad9b4 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -42,10 +42,17 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); +extern void lock_ipi_call_lock(void); +extern void unlock_ipi_call_lock(void); #define MAX_APICID 256 extern u8 x86_cpu_to_apicid[]; +#ifdef CONFIG_HOTPLUG_CPU +extern void cpu_exit_clear(void); +extern void cpu_uninit(void); +#endif + /* * This function is needed by all SMP systems. It must _always_ be valid * from the initial startup. We map APIC_BASE very early in page_setup(), @@ -83,6 +90,9 @@ static __inline int logical_smp_processor_id(void) } #endif + +extern int __cpu_disable(void); +extern void __cpu_die(unsigned int cpu); #endif /* !__ASSEMBLY__ */ #define NO_PROC_ID 0xFF /* No processor magic marker */ diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index 6d0f675..2461b73 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -74,11 +74,14 @@ static inline int node_to_first_cpu(int node) .imbalance_pct = 125, \ .cache_hot_time = (10*1000000), \ .cache_nice_tries = 1, \ + .busy_idx = 3, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ .per_cpu_gain = 100, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_EXEC \ - | SD_BALANCE_NEWIDLE \ - | SD_WAKE_IDLE \ + | SD_BALANCE_FORK \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 1, \ diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h index 6f516e7..cd2cf76 100644 --- a/include/asm-ia64/system.h +++ b/include/asm-ia64/system.h @@ -183,8 +183,6 @@ do { \ #ifdef __KERNEL__ -#define prepare_to_switch() do { } while(0) - #ifdef CONFIG_IA32_SUPPORT # define IS_IA32_PROCESS(regs) (ia64_psr(regs)->is != 0) #else @@ -274,13 +272,7 @@ extern void ia64_load_extra (struct task_struct *task); * of that CPU which will not be released, because there we wait for the * tasklist_lock to become available. */ -#define prepare_arch_switch(rq, next) \ -do { \ - spin_lock(&(next)->switch_lock); \ - spin_unlock(&(rq)->lock); \ -} while (0) -#define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock) -#define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) +#define __ARCH_WANT_UNLOCKED_CTXSW #define ia64_platform_is(x) (strcmp(x, platform_name) == 0) diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h index 21cf351..4e64c2a 100644 --- a/include/asm-ia64/topology.h +++ b/include/asm-ia64/topology.h @@ -42,25 +42,54 @@ void build_cpu_to_node_map(void); +#define SD_CPU_INIT (struct sched_domain) { \ + .span = CPU_MASK_NONE, \ + .parent = NULL, \ + .groups = NULL, \ + .min_interval = 1, \ + .max_interval = 4, \ + .busy_factor = 64, \ + .imbalance_pct = 125, \ + .cache_hot_time = (10*1000000), \ + .per_cpu_gain = 100, \ + .cache_nice_tries = 2, \ + .busy_idx = 2, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ + .flags = SD_LOAD_BALANCE \ + | SD_BALANCE_NEWIDLE \ + | SD_BALANCE_EXEC \ + | SD_WAKE_AFFINE, \ + .last_balance = jiffies, \ + .balance_interval = 1, \ + .nr_balance_failed = 0, \ +} + /* sched_domains SD_NODE_INIT for IA64 NUMA machines */ #define SD_NODE_INIT (struct sched_domain) { \ .span = CPU_MASK_NONE, \ .parent = NULL, \ .groups = NULL, \ - .min_interval = 80, \ - .max_interval = 320, \ - .busy_factor = 320, \ + .min_interval = 8, \ + .max_interval = 8*(min(num_online_cpus(), 32)), \ + .busy_factor = 64, \ .imbalance_pct = 125, \ .cache_hot_time = (10*1000000), \ - .cache_nice_tries = 1, \ + .cache_nice_tries = 2, \ + .busy_idx = 3, \ + .idle_idx = 2, \ + .newidle_idx = 0, /* unused */ \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ .per_cpu_gain = 100, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_EXEC \ - | SD_BALANCE_NEWIDLE \ - | SD_WAKE_IDLE \ + | SD_BALANCE_FORK \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ - .balance_interval = 1, \ + .balance_interval = 64, \ .nr_balance_failed = 0, \ } @@ -69,17 +98,21 @@ void build_cpu_to_node_map(void); .span = CPU_MASK_NONE, \ .parent = NULL, \ .groups = NULL, \ - .min_interval = 80, \ - .max_interval = 320, \ - .busy_factor = 320, \ - .imbalance_pct = 125, \ + .min_interval = 64, \ + .max_interval = 64*num_online_cpus(), \ + .busy_factor = 128, \ + .imbalance_pct = 133, \ .cache_hot_time = (10*1000000), \ .cache_nice_tries = 1, \ + .busy_idx = 3, \ + .idle_idx = 3, \ + .newidle_idx = 0, /* unused */ \ + .wake_idx = 0, /* unused */ \ + .forkexec_idx = 0, /* unused */ \ .per_cpu_gain = 100, \ - .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_EXEC, \ + .flags = SD_LOAD_BALANCE, \ .last_balance = jiffies, \ - .balance_interval = 100*(63+num_online_cpus())/64, \ + .balance_interval = 64, \ .nr_balance_failed = 0, \ } diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h index 29ee13b..d721143 100644 --- a/include/asm-mips/mmzone.h +++ b/include/asm-mips/mmzone.h @@ -8,6 +8,8 @@ #include <asm/page.h> #include <mmzone.h> +#ifdef CONFIG_DISCONTIGMEM + #define kvaddr_to_nid(kvaddr) pa_to_nid(__pa(kvaddr)) #define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT) @@ -36,4 +38,6 @@ /* XXX: FIXME -- wli */ #define kern_addr_valid(addr) (0) +#endif /* CONFIG_DISCONTIGMEM */ + #endif /* _ASM_MMZONE_H_ */ diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index d1bf824..5cae35c 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -127,7 +127,7 @@ static __inline__ int get_order(unsigned long size) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) -#ifndef CONFIG_DISCONTIGMEM +#ifndef CONFIG_NEED_MULTIPLE_NODES #define pfn_to_page(pfn) (mem_map + (pfn)) #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) #define pfn_valid(pfn) ((pfn) < max_mapnr) diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index 8788432..e76ccd6 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -350,7 +350,7 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, __update_cache(vma, address, pte); } -#ifndef CONFIG_DISCONTIGMEM +#ifndef CONFIG_NEED_MULTIPLE_NODES #define kern_addr_valid(addr) (1) #endif diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 888fd89..169f3d4 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -422,16 +422,10 @@ extern void __die_if_kernel(const char *, struct pt_regs *, const char *file, extern int stop_a_enabled; /* - * Taken from include/asm-ia64/system.h; prevents deadlock on SMP + * See include/asm-ia64/system.h; prevents deadlock on SMP * systems. */ -#define prepare_arch_switch(rq, next) \ -do { \ - spin_lock(&(next)->switch_lock); \ - spin_unlock(&(rq)->lock); \ -} while (0) -#define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock) -#define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) +#define __ARCH_WANT_UNLOCKED_CTXSW #define arch_align_stack(x) (x) diff --git a/include/asm-ppc/fsl_ocp.h b/include/asm-ppc/fsl_ocp.h deleted file mode 100644 index 050fbba..0000000 --- a/include/asm-ppc/fsl_ocp.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * include/asm-ppc/fsl_ocp.h - * - * Definitions for the on-chip peripherals on Freescale PPC processors - * - * Maintainer: Kumar Gala (kumar.gala@freescale.com) - * - * Copyright 2004 Freescale Semiconductor, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifdef __KERNEL__ -#ifndef __ASM_FS_OCP_H__ -#define __ASM_FS_OCP_H__ - -/* A table of information for supporting the Gianfar Ethernet Controller - * This helps identify which enet controller we are dealing with, - * and what type of enet controller it is - */ -struct ocp_gfar_data { - uint interruptTransmit; - uint interruptError; - uint interruptReceive; - uint interruptPHY; - uint flags; - uint phyid; - uint phyregidx; - unsigned char mac_addr[6]; -}; - -/* Flags in the flags field */ -#define GFAR_HAS_COALESCE 0x20 -#define GFAR_HAS_RMON 0x10 -#define GFAR_HAS_MULTI_INTR 0x08 -#define GFAR_FIRM_SET_MACADDR 0x04 -#define GFAR_HAS_PHY_INTR 0x02 /* if not set use a timer */ -#define GFAR_HAS_GIGABIT 0x01 - -/* Data structure for I2C support. Just contains a couple flags - * to distinguish various I2C implementations*/ -struct ocp_fs_i2c_data { - uint flags; -}; - -/* Flags for I2C */ -#define FS_I2C_SEPARATE_DFSRR 0x02 -#define FS_I2C_CLOCK_5200 0x01 - -#endif /* __ASM_FS_OCP_H__ */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/kexec.h b/include/asm-ppc/kexec.h new file mode 100644 index 0000000..7319131 --- /dev/null +++ b/include/asm-ppc/kexec.h @@ -0,0 +1,38 @@ +#ifndef _PPC_KEXEC_H +#define _PPC_KEXEC_H + +#ifdef CONFIG_KEXEC + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct + * calculation for the amount of memory directly mappable into the + * kernel memory space. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE + +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_PPC + +#ifndef __ASSEMBLY__ + +struct kimage; + +extern void machine_kexec_simple(struct kimage *image); + +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_KEXEC */ + +#endif /* _PPC_KEXEC_H */ diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index b78d408..1d4ab70 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -4,6 +4,7 @@ #include <linux/config.h> #include <linux/init.h> +#include <linux/kexec.h> #include <asm/setup.h> #include <asm/page.h> @@ -114,6 +115,36 @@ struct machdep_calls { /* functions for dealing with other cpus */ struct smp_ops_t *smp_ops; #endif /* CONFIG_SMP */ + +#ifdef CONFIG_KEXEC + /* Called to shutdown machine specific hardware not already controlled + * by other drivers. + * XXX Should we move this one out of kexec scope? + */ + void (*machine_shutdown)(void); + + /* Called to do the minimal shutdown needed to run a kexec'd kernel + * to run successfully. + * XXX Should we move this one out of kexec scope? + */ + void (*machine_crash_shutdown)(void); + + /* Called to do what every setup is needed on image and the + * reboot code buffer. Returns 0 on success. + * Provide your own (maybe dummy) implementation if your platform + * claims to support kexec. + */ + int (*machine_kexec_prepare)(struct kimage *image); + + /* Called to handle any machine specific cleanup on image */ + void (*machine_kexec_cleanup)(struct kimage *image); + + /* Called to perform the _real_ kexec. + * Do NOT allocate memory or fail here. We are past the point of + * no return. + */ + void (*machine_kexec)(struct kimage *image); +#endif /* CONFIG_KEXEC */ }; extern struct machdep_calls ppc_md; diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h index d465aee..9205db4 100644 --- a/include/asm-ppc/mmu.h +++ b/include/asm-ppc/mmu.h @@ -405,7 +405,7 @@ typedef struct _P601_BAT { #define MAS0_TLBSEL(x) ((x << 28) & 0x30000000) #define MAS0_ESEL(x) ((x << 16) & 0x0FFF0000) -#define MAS0_NV 0x00000FFF +#define MAS0_NV(x) ((x) & 0x00000FFF) #define MAS1_VALID 0x80000000 #define MAS1_IPROT 0x40000000 diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index 9222fa6..ccabbce 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -63,7 +63,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) #define LAST_CONTEXT 255 #define FIRST_CONTEXT 1 -#elif defined(CONFIG_E500) +#elif defined(CONFIG_E200) || defined(CONFIG_E500) #define NO_CONTEXT 256 #define LAST_CONTEXT 255 #define FIRST_CONTEXT 1 diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h index c726f18..983116f 100644 --- a/include/asm-ppc/ocp.h +++ b/include/asm-ppc/ocp.h @@ -202,10 +202,6 @@ static DEVICE_ATTR(name##_##field, S_IRUGO, show_##name##_##field, NULL); #include <asm/ibm_ocp.h> #endif -#ifdef CONFIG_FSL_OCP -#include <asm/fsl_ocp.h> -#endif - #endif /* CONFIG_PPC_OCP */ #endif /* __OCP_H__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h index 13fa8e7..f76221d 100644 --- a/include/asm-ppc/ppc_asm.h +++ b/include/asm-ppc/ppc_asm.h @@ -174,6 +174,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #define CLR_TOP32(r) #endif /* CONFIG_PPC64BRIDGE */ +#define RFCI .long 0x4c000066 /* rfci instruction */ +#define RFDI .long 0x4c00004e /* rfdi instruction */ #define RFMCI .long 0x4c00004c /* rfmci instruction */ #ifdef CONFIG_IBM405_ERR77 diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h index c418aab..88b4222 100644 --- a/include/asm-ppc/reg.h +++ b/include/asm-ppc/reg.h @@ -160,6 +160,7 @@ #define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */ #define HID0_DCI (1<<10) /* Data Cache Invalidate */ #define HID0_SPD (1<<9) /* Speculative disable */ +#define HID0_DAPUEN (1<<8) /* Debug APU enable */ #define HID0_SGE (1<<7) /* Store Gathering Enable */ #define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */ #define HID0_DFCA (1<<6) /* Data Cache Flush Assist */ diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h index 45c5e6f..00ad9c7 100644 --- a/include/asm-ppc/reg_booke.h +++ b/include/asm-ppc/reg_booke.h @@ -165,6 +165,8 @@ do { \ #define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */ #define SPRN_MCSR 0x23C /* Machine Check Status Register */ #define SPRN_MCAR 0x23D /* Machine Check Address Register */ +#define SPRN_DSRR0 0x23E /* Debug Save and Restore Register 0 */ +#define SPRN_DSRR1 0x23F /* Debug Save and Restore Register 1 */ #define SPRN_MAS0 0x270 /* MMU Assist Register 0 */ #define SPRN_MAS1 0x271 /* MMU Assist Register 1 */ #define SPRN_MAS2 0x272 /* MMU Assist Register 2 */ @@ -264,6 +266,17 @@ do { \ #define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */ #define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */ #endif +#ifdef CONFIG_E200 +#define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ +#define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */ +#define MCSR_CPERR 0x10000000UL /* Cache Parity Error */ +#define MCSR_EXCP_ERR 0x08000000UL /* ISI, ITLB, or Bus Error on 1st insn + fetch for an exception handler */ +#define MCSR_BUS_IRERR 0x00000010UL /* Read Bus Error on instruction fetch*/ +#define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */ +#define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered + store or cache line push */ +#endif /* Bit definitions for the DBSR. */ /* @@ -311,6 +324,7 @@ do { \ #define ESR_ST 0x00800000 /* Store Operation */ #define ESR_DLK 0x00200000 /* Data Cache Locking */ #define ESR_ILK 0x00100000 /* Instr. Cache Locking */ +#define ESR_PUO 0x00040000 /* Unimplemented Operation exception */ #define ESR_BO 0x00020000 /* Byte Ordering */ /* Bit definitions related to the DBCR0. */ @@ -387,10 +401,12 @@ do { \ #define ICCR_CACHE 1 /* Cacheable */ /* Bit definitions for L1CSR0. */ +#define L1CSR0_CLFC 0x00000100 /* Cache Lock Bits Flash Clear */ #define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */ +#define L1CSR0_CFI 0x00000002 /* Cache Flash Invalidate */ #define L1CSR0_DCE 0x00000001 /* Data Cache Enable */ -/* Bit definitions for L1CSR0. */ +/* Bit definitions for L1CSR1. */ #define L1CSR1_ICLFR 0x00000100 /* Instr Cache Lock Bits Flash Reset */ #define L1CSR1_ICFI 0x00000002 /* Instr Cache Flash Invalidate */ #define L1CSR1_ICE 0x00000001 /* Instr Cache Enable */ diff --git a/include/asm-ppc64/kdebug.h b/include/asm-ppc64/kdebug.h index 4886342..d383d16 100644 --- a/include/asm-ppc64/kdebug.h +++ b/include/asm-ppc64/kdebug.h @@ -17,7 +17,7 @@ struct die_args { /* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_kernel - + If you really want to do it first unregister - then synchronize_sched - then free. */ int register_die_notifier(struct notifier_block *nb); diff --git a/include/asm-ppc64/kexec.h b/include/asm-ppc64/kexec.h new file mode 100644 index 0000000..511908a --- /dev/null +++ b/include/asm-ppc64/kexec.h @@ -0,0 +1,41 @@ +#ifndef _PPC64_KEXEC_H +#define _PPC64_KEXEC_H + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + */ + +/* Maximum physical address we can use pages from */ +/* XXX: since we copy virt we can use any page we allocate */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) + +/* Maximum address we can reach in physical address mode */ +/* XXX: I want to allow initrd in highmem. otherwise set to rmo on lpar */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) + +/* Maximum address we can use for the control code buffer */ +/* XXX: unused today, ppc32 uses TASK_SIZE, probably left over from use_mm */ +#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL) + +/* XXX: today we don't use this at all, althogh we have a static stack */ +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_PPC64 + +#define MAX_NOTE_BYTES 1024 + +#ifndef __ASSEMBLY__ + +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; + +extern note_buf_t crash_notes[]; + +extern void kexec_smp_wait(void); /* get and clear naca physid, wait for + master to copy new code to 0 */ + +#endif /* __ASSEMBLY__ */ +#endif /* _PPC_KEXEC_H */ + diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index 553b2ea..9cdad3e 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -86,6 +86,7 @@ struct machdep_calls { void (*init_IRQ)(void); int (*get_irq)(struct pt_regs *); + void (*cpu_irq_down)(void); /* PCI stuff */ void (*pcibios_fixup)(void); diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h index 9d03a98..f373de5 100644 --- a/include/asm-ppc64/mmu.h +++ b/include/asm-ppc64/mmu.h @@ -181,6 +181,28 @@ static inline void tlbiel(unsigned long va) asm volatile("ptesync": : :"memory"); } +static inline unsigned long slot2va(unsigned long avpn, unsigned long large, + unsigned long secondary, unsigned long slot) +{ + unsigned long va; + + va = avpn << 23; + + if (!large) { + unsigned long vpi, pteg; + + pteg = slot / HPTES_PER_GROUP; + if (secondary) + pteg = ~pteg; + + vpi = ((va >> 28) ^ pteg) & htab_hash_mask; + + va |= vpi << PAGE_SHIFT; + } + + return va; +} + /* * Handle a fault by adding an HPTE. If the address can't be determined * to be valid via Linux page tables, return 1. If handled return 0 diff --git a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h index fdec5e7..0c45e14 100644 --- a/include/asm-ppc64/xics.h +++ b/include/asm-ppc64/xics.h @@ -17,6 +17,7 @@ void xics_init_IRQ(void); int xics_get_irq(struct pt_regs *); void xics_setup_cpu(void); +void xics_teardown_cpu(void); void xics_cause_IPI(int cpu); void xics_request_IPIs(void); void xics_migrate_irqs_away(void); diff --git a/include/asm-s390/cpcmd.h b/include/asm-s390/cpcmd.h index 1d33c5da..1fcf65b 100644 --- a/include/asm-s390/cpcmd.h +++ b/include/asm-s390/cpcmd.h @@ -11,14 +11,28 @@ #define __CPCMD__ /* + * the lowlevel function for cpcmd * the caller of __cpcmd has to ensure that the response buffer is below 2 GB */ -extern void __cpcmd(char *cmd, char *response, int rlen); +extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code); #ifndef __s390x__ #define cpcmd __cpcmd #else -extern void cpcmd(char *cmd, char *response, int rlen); +/* + * cpcmd is the in-kernel interface for issuing CP commands + * + * cmd: null-terminated command string, max 240 characters + * response: response buffer for VM's textual response + * rlen: size of the response buffer, cpcmd will not exceed this size + * but will cap the output, if its too large. Everything that + * did not fit into the buffer will be silently dropped + * response_code: return pointer for VM's error code + * return value: the size of the response. The caller can check if the buffer + * was large enough by comparing the return value and rlen + * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep + */ +extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code); #endif /*__s390x__*/ #endif diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h index 6bbcdea..92360d9 100644 --- a/include/asm-s390/debug.h +++ b/include/asm-s390/debug.h @@ -9,6 +9,8 @@ #ifndef DEBUG_H #define DEBUG_H +#include <linux/config.h> +#include <linux/fs.h> #include <linux/string.h> /* Note: @@ -31,19 +33,18 @@ struct __debug_entry{ } __attribute__((packed)); -#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */ +#define __DEBUG_FEATURE_VERSION 2 /* version of debug feature */ #ifdef __KERNEL__ #include <linux/spinlock.h> #include <linux/kernel.h> #include <linux/time.h> -#include <linux/proc_fs.h> #define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */ #define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */ #define DEBUG_FLUSH_ALL -1 /* parameter to flush all areas */ #define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ -#define DEBUG_MAX_PROCF_LEN 64 /* max length for a proc file name */ +#define DEBUG_MAX_NAME_LEN 64 /* max length for a debugfs file name */ #define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ @@ -64,16 +65,17 @@ typedef struct debug_info { spinlock_t lock; int level; int nr_areas; - int page_order; + int pages_per_area; int buf_size; int entry_size; - debug_entry_t** areas; + debug_entry_t*** areas; int active_area; - int *active_entry; - struct proc_dir_entry* proc_root_entry; - struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS]; + int *active_pages; + int *active_entries; + struct dentry* debugfs_root_entry; + struct dentry* debugfs_entries[DEBUG_MAX_VIEWS]; struct debug_view* views[DEBUG_MAX_VIEWS]; - char name[DEBUG_MAX_PROCF_LEN]; + char name[DEBUG_MAX_NAME_LEN]; } debug_info_t; typedef int (debug_header_proc_t) (debug_info_t* id, @@ -98,7 +100,7 @@ int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view, int area, debug_entry_t* entry, char* out_buf); struct debug_view { - char name[DEBUG_MAX_PROCF_LEN]; + char name[DEBUG_MAX_NAME_LEN]; debug_prolog_proc_t* prolog_proc; debug_header_proc_t* header_proc; debug_format_proc_t* format_proc; @@ -120,7 +122,7 @@ debug_entry_t* debug_exception_common(debug_info_t* id, int level, /* Debug Feature API: */ -debug_info_t* debug_register(char* name, int pages_index, int nr_areas, +debug_info_t* debug_register(char* name, int pages, int nr_areas, int buf_size); void debug_unregister(debug_info_t* id); @@ -132,7 +134,8 @@ void debug_stop_all(void); extern inline debug_entry_t* debug_event(debug_info_t* id, int level, void* data, int length) { - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_event_common(id,level,data,length); } @@ -140,7 +143,8 @@ extern inline debug_entry_t* debug_int_event(debug_info_t* id, int level, unsigned int tag) { unsigned int t=tag; - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_event_common(id,level,&t,sizeof(unsigned int)); } @@ -148,14 +152,16 @@ extern inline debug_entry_t * debug_long_event (debug_info_t* id, int level, unsigned long tag) { unsigned long t=tag; - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_event_common(id,level,&t,sizeof(unsigned long)); } extern inline debug_entry_t* debug_text_event(debug_info_t* id, int level, const char* txt) { - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_event_common(id,level,txt,strlen(txt)); } @@ -167,7 +173,8 @@ debug_sprintf_event(debug_info_t* id,int level,char *string,...) extern inline debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, int length) { - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_exception_common(id,level,data,length); } @@ -175,7 +182,8 @@ extern inline debug_entry_t* debug_int_exception(debug_info_t* id, int level, unsigned int tag) { unsigned int t=tag; - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_exception_common(id,level,&t,sizeof(unsigned int)); } @@ -183,14 +191,16 @@ extern inline debug_entry_t * debug_long_exception (debug_info_t* id, int level, unsigned long tag) { unsigned long t=tag; - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_exception_common(id,level,&t,sizeof(unsigned long)); } extern inline debug_entry_t* debug_text_exception(debug_info_t* id, int level, const char* txt) { - if ((!id) || (level > id->level)) return NULL; + if ((!id) || (level > id->level) || (id->pages_per_area == 0)) + return NULL; return debug_exception_common(id,level,txt,strlen(txt)); } diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h new file mode 100644 index 0000000..54cf7d9 --- /dev/null +++ b/include/asm-s390/kexec.h @@ -0,0 +1,42 @@ +/* + * include/asm-s390/kexec.h + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> + * + */ + +#ifndef _S390_KEXEC_H +#define _S390_KEXEC_H + +#include <asm/page.h> +#include <asm/processor.h> +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) + +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) + +/* Maximum address we can use for the control pages */ +/* Not more than 2GB */ +#define KEXEC_CONTROL_MEMORY_LIMIT (1<<31) + +/* Allocate one page for the pdp and the second for the code */ +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_S390 + +#define MAX_NOTE_BYTES 1024 +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; + +extern note_buf_t crash_notes[]; + +#endif /*_S390_KEXEC_H */ diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index df5172f..76b5b19 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -109,10 +109,14 @@ #ifndef __s390x__ #define __LC_PFAULT_INTPARM 0x080 +#define __LC_CPU_TIMER_SAVE_AREA 0x0D8 #define __LC_AREGS_SAVE_AREA 0x120 +#define __LC_GPREGS_SAVE_AREA 0x180 #define __LC_CREGS_SAVE_AREA 0x1C0 #else /* __s390x__ */ #define __LC_PFAULT_INTPARM 0x11B8 +#define __LC_GPREGS_SAVE_AREA 0x1280 +#define __LC_CPU_TIMER_SAVE_AREA 0x1328 #define __LC_AREGS_SAVE_AREA 0x1340 #define __LC_CREGS_SAVE_AREA 0x1380 #endif /* __s390x__ */ @@ -167,7 +171,8 @@ struct _lowcore __u16 subchannel_nr; /* 0x0ba */ __u32 io_int_parm; /* 0x0bc */ __u32 io_int_word; /* 0x0c0 */ - __u8 pad3[0xD8-0xC4]; /* 0x0c4 */ + __u8 pad3[0xD4-0xC4]; /* 0x0c4 */ + __u32 extended_save_area_addr; /* 0x0d4 */ __u32 cpu_timer_save_area[2]; /* 0x0d8 */ __u32 clock_comp_save_area[2]; /* 0x0e0 */ __u32 mcck_interruption_code[2]; /* 0x0e8 */ diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index fb46e90..8bd14de 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -207,6 +207,18 @@ unsigned long get_wchan(struct task_struct *p); #endif /* __s390x__ */ /* + * Set PSW to specified value. + */ +static inline void __load_psw(psw_t psw) +{ +#ifndef __s390x__ + asm volatile ("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); +#else + asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); +#endif +} + +/* * Set PSW mask to specified value, while leaving the * PSW addr pointing to the next instruction. */ @@ -214,8 +226,8 @@ unsigned long get_wchan(struct task_struct *p); static inline void __load_psw_mask (unsigned long mask) { unsigned long addr; - psw_t psw; + psw.mask = mask; #ifndef __s390x__ @@ -241,30 +253,8 @@ static inline void __load_psw_mask (unsigned long mask) */ static inline void enabled_wait(void) { - unsigned long reg; - psw_t wait_psw; - - wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT | - PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY; -#ifndef __s390x__ - asm volatile ( - " basr %0,0\n" - "0: la %0,1f-0b(%0)\n" - " st %0,4(%1)\n" - " oi 4(%1),0x80\n" - " lpsw 0(%1)\n" - "1:" - : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw) - : "memory", "cc" ); -#else /* __s390x__ */ - asm volatile ( - " larl %0,0f\n" - " stg %0,8(%1)\n" - " lpswe 0(%1)\n" - "0:" - : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw) - : "memory", "cc" ); -#endif /* __s390x__ */ + __load_psw_mask(PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT | + PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY); } /* @@ -273,13 +263,11 @@ static inline void enabled_wait(void) static inline void disabled_wait(unsigned long code) { - char psw_buffer[2*sizeof(psw_t)]; unsigned long ctl_buf; - psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1) - & -sizeof(psw_t)); + psw_t dw_psw; - dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT; - dw_psw->addr = code; + dw_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; + dw_psw.addr = code; /* * Store status and then load disabled wait psw, * the processor is dead afterwards @@ -301,7 +289,7 @@ static inline void disabled_wait(unsigned long code) " oi 0x1c0,0x10\n" /* fake protection bit */ " lpsw 0(%1)" : "=m" (ctl_buf) - : "a" (dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" ); + : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" ); #else /* __s390x__ */ asm volatile (" stctg 0,0,0(%2)\n" " ni 4(%2),0xef\n" /* switch off protection */ @@ -333,7 +321,7 @@ static inline void disabled_wait(unsigned long code) " oi 0x384(1),0x10\n" /* fake protection bit */ " lpswe 0(%1)" : "=m" (ctl_buf) - : "a" (dw_psw), "a" (&ctl_buf), + : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0", "1"); #endif /* __s390x__ */ } diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 4eff8f2..fc7c96e 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h @@ -276,7 +276,7 @@ typedef struct #endif /* __s390x__ */ #define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \ - PSW_DEFAULT_KEY) + PSW_MASK_MCHECK | PSW_DEFAULT_KEY) #define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ PSW_MASK_PSTATE | PSW_DEFAULT_KEY) diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index 81514d7..b4a9f05 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -16,6 +16,7 @@ #include <asm/types.h> #include <asm/ptrace.h> #include <asm/setup.h> +#include <asm/processor.h> #ifdef __KERNEL__ @@ -103,29 +104,18 @@ static inline void restore_access_regs(unsigned int *acrs) prev = __switch_to(prev,next); \ } while (0) -#define prepare_arch_switch(rq, next) do { } while(0) -#define task_running(rq, p) ((rq)->curr == (p)) - #ifdef CONFIG_VIRT_CPU_ACCOUNTING extern void account_user_vtime(struct task_struct *); extern void account_system_vtime(struct task_struct *); - -#define finish_arch_switch(rq, prev) do { \ - set_fs(current->thread.mm_segment); \ - spin_unlock(&(rq)->lock); \ - account_system_vtime(prev); \ - local_irq_enable(); \ -} while (0) - #else +#define account_system_vtime(prev) do { } while (0) +#endif #define finish_arch_switch(rq, prev) do { \ set_fs(current->thread.mm_segment); \ - spin_unlock_irq(&(rq)->lock); \ + account_system_vtime(prev); \ } while (0) -#endif - #define nop() __asm__ __volatile__ ("nop") #define xchg(ptr,x) \ @@ -331,9 +321,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) #ifdef __s390x__ -#define __load_psw(psw) \ - __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" ); - #define __ctl_load(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ __asm__ __volatile__ ( \ @@ -390,9 +377,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) #else /* __s390x__ */ -#define __load_psw(psw) \ - __asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" ); - #define __ctl_load(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ __asm__ __volatile__ ( \ @@ -451,6 +435,20 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) /* For spinlocks etc */ #define local_irq_save(x) ((x) = local_irq_disable()) +/* + * Use to set psw mask except for the first byte which + * won't be changed by this function. + */ +static inline void +__set_psw_mask(unsigned long mask) +{ + local_save_flags(mask); + __load_psw_mask(mask); +} + +#define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS) +#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK) + #ifdef CONFIG_SMP extern void smp_ctl_set_bit(int cr, int bit); diff --git a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h index fe101d4..6c18a3f 100644 --- a/include/asm-s390/thread_info.h +++ b/include/asm-s390/thread_info.h @@ -96,6 +96,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ #define TIF_SINGLE_STEP 6 /* deliver sigtrap on return to user */ +#define TIF_MCCK_PENDING 7 /* machine check handling is pending */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ @@ -109,6 +110,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_RESTART_SVC (1<<TIF_RESTART_SVC) #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP) +#define _TIF_MCCK_PENDING (1<<TIF_MCCK_PENDING) #define _TIF_USEDFPU (1<<TIF_USEDFPU) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) #define _TIF_31BIT (1<<TIF_31BIT) diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index f1a204f..363db45 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -269,7 +269,7 @@ #define __NR_mq_timedreceive 274 #define __NR_mq_notify 275 #define __NR_mq_getsetattr 276 -/* Number 277 is reserved for new sys_kexec_load */ +#define __NR_kexec_load 277 #define __NR_add_key 278 #define __NR_request_key 279 #define __NR_keyctl 280 diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index 80cf20c..898562e 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.h @@ -101,7 +101,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, * SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work) * XXX WTF is the above comment? Found in late teen 2.4.x. */ -#define prepare_arch_switch(rq, next) do { \ +#define prepare_arch_switch(next) do { \ __asm__ __volatile__( \ ".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \ "save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \ @@ -109,8 +109,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, "save %sp, -0x40, %sp\n\t" \ "restore; restore; restore; restore; restore; restore; restore"); \ } while(0) -#define finish_arch_switch(rq, next) spin_unlock_irq(&(rq)->lock) -#define task_running(rq, p) ((rq)->curr == (p)) /* Much care has gone into this code, do not touch it. * diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h index f70d3da..6321f5a 100644 --- a/include/asm-sparc64/kdebug.h +++ b/include/asm-sparc64/kdebug.h @@ -16,7 +16,7 @@ struct die_args { }; /* Note - you should never unregister because that can race with NMIs. - * If you really want to do it first unregister - then synchronize_kernel + * If you really want to do it first unregister - then synchronize_sched * - then free. */ int register_die_notifier(struct notifier_block *nb); diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index fd12ca3..f9be2c5 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -139,19 +139,13 @@ extern void __flushw_user(void); #define flush_user_windows flushw_user #define flush_register_windows flushw_all -#define prepare_arch_switch(rq, next) \ -do { spin_lock(&(next)->switch_lock); \ - spin_unlock(&(rq)->lock); \ +/* Don't hold the runqueue lock over context switch */ +#define __ARCH_WANT_UNLOCKED_CTXSW +#define prepare_arch_switch(next) \ +do { \ flushw_all(); \ } while (0) -#define finish_arch_switch(rq, prev) \ -do { spin_unlock_irq(&(prev)->switch_lock); \ -} while (0) - -#define task_running(rq, p) \ - ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) - /* See what happens when you design the chip correctly? * * We tell gcc we clobber all non-fixed-usage registers except diff --git a/include/asm-sparc64/termios.h b/include/asm-sparc64/termios.h index 8effce0..9777a9c 100644 --- a/include/asm-sparc64/termios.h +++ b/include/asm-sparc64/termios.h @@ -100,16 +100,17 @@ struct winsize { #define user_termio_to_kernel_termios(termios, termio) \ ({ \ unsigned short tmp; \ - get_user(tmp, &(termio)->c_iflag); \ + int err; \ + err = get_user(tmp, &(termio)->c_iflag); \ (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ - get_user(tmp, &(termio)->c_oflag); \ + err |= get_user(tmp, &(termio)->c_oflag); \ (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ - get_user(tmp, &(termio)->c_cflag); \ + err |= get_user(tmp, &(termio)->c_cflag); \ (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ - get_user(tmp, &(termio)->c_lflag); \ + err |= get_user(tmp, &(termio)->c_lflag); \ (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ - copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ - 0; \ + err |= copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ + err; \ }) /* @@ -119,53 +120,56 @@ struct winsize { */ #define kernel_termios_to_user_termio(termio, termios) \ ({ \ - put_user((termios)->c_iflag, &(termio)->c_iflag); \ - put_user((termios)->c_oflag, &(termio)->c_oflag); \ - put_user((termios)->c_cflag, &(termio)->c_cflag); \ - put_user((termios)->c_lflag, &(termio)->c_lflag); \ - put_user((termios)->c_line, &(termio)->c_line); \ - copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ + int err; \ + err = put_user((termios)->c_iflag, &(termio)->c_iflag); \ + err |= put_user((termios)->c_oflag, &(termio)->c_oflag); \ + err |= put_user((termios)->c_cflag, &(termio)->c_cflag); \ + err |= put_user((termios)->c_lflag, &(termio)->c_lflag); \ + err |= put_user((termios)->c_line, &(termio)->c_line); \ + err |= copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ if (!((termios)->c_lflag & ICANON)) { \ - put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \ - put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \ + err |= put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \ + err |= put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \ } \ - 0; \ + err; \ }) #define user_termios_to_kernel_termios(k, u) \ ({ \ - get_user((k)->c_iflag, &(u)->c_iflag); \ - get_user((k)->c_oflag, &(u)->c_oflag); \ - get_user((k)->c_cflag, &(u)->c_cflag); \ - get_user((k)->c_lflag, &(u)->c_lflag); \ - get_user((k)->c_line, &(u)->c_line); \ - copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \ + int err; \ + err = get_user((k)->c_iflag, &(u)->c_iflag); \ + err |= get_user((k)->c_oflag, &(u)->c_oflag); \ + err |= get_user((k)->c_cflag, &(u)->c_cflag); \ + err |= get_user((k)->c_lflag, &(u)->c_lflag); \ + err |= get_user((k)->c_line, &(u)->c_line); \ + err |= copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \ if((k)->c_lflag & ICANON) { \ - get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ - get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ + err |= get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ + err |= get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ } else { \ - get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ - get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ + err |= get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ + err |= get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ } \ - 0; \ + err; \ }) #define kernel_termios_to_user_termios(u, k) \ ({ \ - put_user((k)->c_iflag, &(u)->c_iflag); \ - put_user((k)->c_oflag, &(u)->c_oflag); \ - put_user((k)->c_cflag, &(u)->c_cflag); \ - put_user((k)->c_lflag, &(u)->c_lflag); \ - put_user((k)->c_line, &(u)->c_line); \ - copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \ + int err; \ + err = put_user((k)->c_iflag, &(u)->c_iflag); \ + err |= put_user((k)->c_oflag, &(u)->c_oflag); \ + err |= put_user((k)->c_cflag, &(u)->c_cflag); \ + err |= put_user((k)->c_lflag, &(u)->c_lflag); \ + err |= put_user((k)->c_line, &(u)->c_line); \ + err |= copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \ if(!((k)->c_lflag & ICANON)) { \ - put_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ - put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ + err |= put_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \ + err |= put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \ } else { \ - put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ - put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ + err |= put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \ + err |= put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \ } \ - 0; \ + err; \ }) #endif /* __KERNEL__ */ diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h index 04222f3..fe882b9 100644 --- a/include/asm-um/ptrace-i386.h +++ b/include/asm-um/ptrace-i386.h @@ -32,6 +32,10 @@ #define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r) #define PT_FIX_EXEC_STACK(sp) do ; while(0) +/* Cope with a conditional i386 definition. */ +#undef profile_pc +#define profile_pc(regs) PT_REGS_IP(regs) + #define user_mode(r) UPT_IS_USER(&(r)->regs) #endif diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index e4b1017..16ec82e 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h @@ -77,7 +77,7 @@ static inline void ack_APIC_irq(void) extern int get_maxlvt (void); extern void clear_local_APIC (void); extern void connect_bsp_APIC (void); -extern void disconnect_bsp_APIC (void); +extern void disconnect_bsp_APIC (int virt_wire_setup); extern void disable_local_APIC (void); extern int verify_local_APIC (void); extern void cache_APIC_registers (void); diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h index bfebdb6..9388062 100644 --- a/include/asm-x86_64/apicdef.h +++ b/include/asm-x86_64/apicdef.h @@ -94,7 +94,7 @@ #define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) #define APIC_MODE_FIXED 0x0 #define APIC_MODE_NMI 0x4 -#define APIC_MODE_EXINT 0x7 +#define APIC_MODE_EXTINT 0x7 #define APIC_LVT1 0x360 #define APIC_LVTERR 0x370 #define APIC_TMICT 0x380 diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h index 3af50b3..eb3b7aa 100644 --- a/include/asm-x86_64/irq.h +++ b/include/asm-x86_64/irq.h @@ -52,4 +52,9 @@ struct irqaction; struct pt_regs; int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); +#ifdef CONFIG_HOTPLUG_CPU +#include <linux/cpumask.h> +extern void fixup_irqs(cpumask_t map); +#endif + #endif /* _ASM_IRQ_H */ diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index 6277f75..b903419 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h @@ -14,7 +14,7 @@ struct die_args { }; /* Note - you should never unregister because that can race with NMIs. - If you really want to do it first unregister - then synchronize_kernel - then free. + If you really want to do it first unregister - then synchronize_sched - then free. */ int register_die_notifier(struct notifier_block *nb); extern struct notifier_block *die_chain; diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h new file mode 100644 index 0000000..42d2ff1 --- /dev/null +++ b/include/asm-x86_64/kexec.h @@ -0,0 +1,33 @@ +#ifndef _X86_64_KEXEC_H +#define _X86_64_KEXEC_H + +#include <asm/page.h> +#include <asm/proto.h> + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * So far x86_64 is limited to 40 physical address bits. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (0xFFFFFFFFFFUL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL) +/* Maximum address we can use for the control pages */ +#define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL) + +/* Allocate one page for the pdp and the second for the code */ +#define KEXEC_CONTROL_CODE_SIZE (4096UL + 4096UL) + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_X86_64 + +#define MAX_NOTE_BYTES 1024 +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; + +extern note_buf_t crash_notes[]; + +#endif /* _X86_64_KEXEC_H */ diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index 60130f4..4313187 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h @@ -64,12 +64,14 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) -#define __START_KERNEL 0xffffffff80100000UL +#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START) +#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) #define __START_KERNEL_map 0xffffffff80000000UL #define __PAGE_OFFSET 0xffff810000000000UL #else -#define __START_KERNEL 0xffffffff80100000 +#define __PHYSICAL_START CONFIG_PHYSICAL_START +#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) #define __START_KERNEL_map 0xffffffff80000000 #define __PAGE_OFFSET 0xffff810000000000 #endif /* !__ASSEMBLY__ */ diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index a7425aa..aeb1b73 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h @@ -43,6 +43,8 @@ extern cpumask_t cpu_callout_map; extern void smp_alloc_memory(void); extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; +extern void lock_ipi_call_lock(void); +extern void unlock_ipi_call_lock(void); extern int smp_num_siblings; extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); @@ -77,6 +79,8 @@ extern __inline int hard_smp_processor_id(void) } extern int safe_smp_processor_id(void); +extern int __cpu_disable(void); +extern void __cpu_die(unsigned int cpu); #endif /* !ASSEMBLY */ diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h index ec74580..bb9f405 100644 --- a/include/asm-x86_64/suspend.h +++ b/include/asm-x86_64/suspend.h @@ -16,7 +16,7 @@ arch_prepare_suspend(void) struct saved_context { u16 ds, es, fs, gs, ss; unsigned long gs_base, gs_kernel_base, fs_base; - unsigned long cr0, cr2, cr3, cr4; + unsigned long cr0, cr2, cr3, cr4, cr8; u16 gdt_pad; u16 gdt_limit; unsigned long gdt_base; diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index 8f77e9f..c1bc3fa 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -39,12 +39,16 @@ extern int __node_distance(int, int); .busy_factor = 32, \ .imbalance_pct = 125, \ .cache_hot_time = (10*1000000), \ - .cache_nice_tries = 1, \ + .cache_nice_tries = 2, \ + .busy_idx = 3, \ + .idle_idx = 2, \ + .newidle_idx = 0, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ .per_cpu_gain = 100, \ .flags = SD_LOAD_BALANCE \ - | SD_BALANCE_NEWIDLE \ + | SD_BALANCE_FORK \ | SD_BALANCE_EXEC \ - | SD_WAKE_IDLE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 1, \ diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 3c9af6f..d767adc 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h @@ -552,7 +552,7 @@ __SYSCALL(__NR_mq_notify, sys_mq_notify) #define __NR_mq_getsetattr 245 __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr) #define __NR_kexec_load 246 -__SYSCALL(__NR_kexec_load, sys_ni_syscall) +__SYSCALL(__NR_kexec_load, sys_kexec_load) #define __NR_waitid 247 __SYSCALL(__NR_waitid, sys_waitid) #define __NR_add_key 248 diff --git a/include/linux/a.out.h b/include/linux/a.out.h index af8a1df..f913cc3 100644 --- a/include/linux/a.out.h +++ b/include/linux/a.out.h @@ -138,7 +138,7 @@ enum machine_type { #endif #endif -#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) +#define _N_SEGMENT_ROUND(x) ALIGN(x, SEGMENT_SIZE) #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 6027214..b54a034 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -539,15 +539,12 @@ extern void generic_make_request(struct bio *bio); extern void blk_put_request(struct request *); extern void blk_end_sync_rq(struct request *rq); extern void blk_attempt_remerge(request_queue_t *, struct request *); -extern void __blk_attempt_remerge(request_queue_t *, struct request *); extern struct request *blk_get_request(request_queue_t *, int, int); extern void blk_insert_request(request_queue_t *, struct request *, int, void *); extern void blk_requeue_request(request_queue_t *, struct request *); extern void blk_plug_device(request_queue_t *); extern int blk_remove_plug(request_queue_t *); extern void blk_recount_segments(request_queue_t *, struct bio *); -extern int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *); -extern int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *); extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); extern void blk_start_queue(request_queue_t *q); extern void blk_stop_queue(request_queue_t *q); @@ -631,7 +628,6 @@ extern void blk_queue_dma_alignment(request_queue_t *, int); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); extern void blk_queue_ordered(request_queue_t *, int); extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *); -extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *); extern struct request *blk_start_pre_flush(request_queue_t *,struct request *); extern int blk_complete_barrier_rq(request_queue_t *, struct request *, int); extern int blk_complete_barrier_rq_locked(request_queue_t *, struct request *, int); @@ -675,8 +671,6 @@ extern int blkdev_issue_flush(struct block_device *, sector_t *); #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist) -extern void drive_stat_acct(struct request *, int, int); - static inline int queue_hardsect_size(request_queue_t *q) { int retval = 512; diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 500f451..82bd884 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -22,6 +22,10 @@ extern unsigned long min_low_pfn; */ extern unsigned long max_pfn; +#ifdef CONFIG_CRASH_DUMP +extern unsigned long saved_max_pfn; +#endif + /* * node_bootmem_map is a map pointer - the bits represent all physical * memory pages (including holes) on the node. diff --git a/include/linux/cpu.h b/include/linux/cpu.h index fe0298e..e8904c0 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -69,6 +69,7 @@ extern struct semaphore cpucontrol; register_cpu_notifier(&fn##_nb); \ } int cpu_down(unsigned int cpu); +extern int __attribute__((weak)) smp_prepare_cpu(int cpu); #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) #else #define lock_cpu_hotplug() do { } while (0) diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h new file mode 100644 index 0000000..534d750 --- /dev/null +++ b/include/linux/crash_dump.h @@ -0,0 +1,18 @@ +#ifndef LINUX_CRASH_DUMP_H +#define LINUX_CRASH_DUMP_H + +#ifdef CONFIG_CRASH_DUMP +#include <linux/kexec.h> +#include <linux/smp_lock.h> +#include <linux/device.h> +#include <linux/proc_fs.h> + +#define ELFCORE_ADDR_MAX (-1ULL) +extern unsigned long long elfcorehdr_addr; +extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, + unsigned long, int); +extern struct file_operations proc_vmcore_operations; +extern struct proc_dir_entry *proc_vmcore; + +#endif /* CONFIG_CRASH_DUMP */ +#endif /* LINUX_CRASHDUMP_H */ diff --git a/include/linux/dmi.h b/include/linux/dmi.h index d2bcf55..5e93e6d 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -9,6 +9,7 @@ enum dmi_field { DMI_SYS_VENDOR, DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, + DMI_PRODUCT_SERIAL, DMI_BOARD_VENDOR, DMI_BOARD_NAME, DMI_BOARD_VERSION, diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 2a7e6c6..6bece92 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -28,6 +28,7 @@ static inline void *kmap(struct page *page) #define kmap_atomic(page, idx) page_address(page) #define kunmap_atomic(addr, idx) do { } while (0) +#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn)) #define kmap_atomic_to_page(ptr) virt_to_page(ptr) #endif /* CONFIG_HIGHMEM */ diff --git a/include/linux/init.h b/include/linux/init.h index 05c83e0..59008c3 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -229,6 +229,18 @@ void __init parse_early_param(void); #define __devexitdata __exitdata #endif +#ifdef CONFIG_HOTPLUG_CPU +#define __cpuinit +#define __cpuinitdata +#define __cpuexit +#define __cpuexitdata +#else +#define __cpuinit __init +#define __cpuinitdata __initdata +#define __cpuexit __exit +#define __cpuexitdata __exitdata +#endif + /* Functions marked as __devexit may be discarded at kernel link time, depending on config options. Newer versions of binutils detect references from retained sections to discarded sections and flag an error. Pointers to diff --git a/include/linux/init_task.h b/include/linux/init_task.h index a6a8c1a..03206a4 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -108,7 +108,6 @@ extern struct group_info init_groups; .blocked = {{0}}, \ .alloc_lock = SPIN_LOCK_UNLOCKED, \ .proc_lock = SPIN_LOCK_UNLOCKED, \ - .switch_lock = SPIN_LOCK_UNLOCKED, \ .journal_info = NULL, \ .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ } diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e25b970..687ba8c 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -58,15 +58,23 @@ struct completion; * be biten later when the calling function happens to sleep when it is not * supposed to. */ +#ifdef CONFIG_PREEMPT_VOLUNTARY +extern int cond_resched(void); +# define might_resched() cond_resched() +#else +# define might_resched() do { } while (0) +#endif + #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP -#define might_sleep() __might_sleep(__FILE__, __LINE__) -#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0) -void __might_sleep(char *file, int line); + void __might_sleep(char *file, int line); +# define might_sleep() \ + do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0) #else -#define might_sleep() do {} while(0) -#define might_sleep_if(cond) do {} while (0) +# define might_sleep() do { might_resched(); } while (0) #endif +#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0) + #define abs(x) ({ \ int __x = (x); \ (__x < 0) ? -__x : __x; \ diff --git a/include/linux/kexec.h b/include/linux/kexec.h new file mode 100644 index 0000000..c846847 --- /dev/null +++ b/include/linux/kexec.h @@ -0,0 +1,135 @@ +#ifndef LINUX_KEXEC_H +#define LINUX_KEXEC_H + +#ifdef CONFIG_KEXEC +#include <linux/types.h> +#include <linux/list.h> +#include <linux/linkage.h> +#include <linux/compat.h> +#include <asm/kexec.h> + +/* Verify architecture specific macros are defined */ + +#ifndef KEXEC_SOURCE_MEMORY_LIMIT +#error KEXEC_SOURCE_MEMORY_LIMIT not defined +#endif + +#ifndef KEXEC_DESTINATION_MEMORY_LIMIT +#error KEXEC_DESTINATION_MEMORY_LIMIT not defined +#endif + +#ifndef KEXEC_CONTROL_MEMORY_LIMIT +#error KEXEC_CONTROL_MEMORY_LIMIT not defined +#endif + +#ifndef KEXEC_CONTROL_CODE_SIZE +#error KEXEC_CONTROL_CODE_SIZE not defined +#endif + +#ifndef KEXEC_ARCH +#error KEXEC_ARCH not defined +#endif + +/* + * This structure is used to hold the arguments that are used when loading + * kernel binaries. + */ + +typedef unsigned long kimage_entry_t; +#define IND_DESTINATION 0x1 +#define IND_INDIRECTION 0x2 +#define IND_DONE 0x4 +#define IND_SOURCE 0x8 + +#define KEXEC_SEGMENT_MAX 8 +struct kexec_segment { + void __user *buf; + size_t bufsz; + unsigned long mem; /* User space sees this as a (void *) ... */ + size_t memsz; +}; + +#ifdef CONFIG_COMPAT +struct compat_kexec_segment { + compat_uptr_t buf; + compat_size_t bufsz; + compat_ulong_t mem; /* User space sees this as a (void *) ... */ + compat_size_t memsz; +}; +#endif + +struct kimage { + kimage_entry_t head; + kimage_entry_t *entry; + kimage_entry_t *last_entry; + + unsigned long destination; + + unsigned long start; + struct page *control_code_page; + + unsigned long nr_segments; + struct kexec_segment segment[KEXEC_SEGMENT_MAX]; + + struct list_head control_pages; + struct list_head dest_pages; + struct list_head unuseable_pages; + + /* Address of next control page to allocate for crash kernels. */ + unsigned long control_page; + + /* Flags to indicate special processing */ + unsigned int type : 1; +#define KEXEC_TYPE_DEFAULT 0 +#define KEXEC_TYPE_CRASH 1 +}; + + + +/* kexec interface functions */ +extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; +extern int machine_kexec_prepare(struct kimage *image); +extern void machine_kexec_cleanup(struct kimage *image); +extern asmlinkage long sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments, + unsigned long flags); +#ifdef CONFIG_COMPAT +extern asmlinkage long compat_sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct compat_kexec_segment __user *segments, + unsigned long flags); +#endif +extern struct page *kimage_alloc_control_pages(struct kimage *image, + unsigned int order); +extern void crash_kexec(struct pt_regs *); +int kexec_should_crash(struct task_struct *); +extern struct kimage *kexec_image; + +#define KEXEC_ON_CRASH 0x00000001 +#define KEXEC_ARCH_MASK 0xffff0000 + +/* These values match the ELF architecture values. + * Unless there is a good reason that should continue to be the case. + */ +#define KEXEC_ARCH_DEFAULT ( 0 << 16) +#define KEXEC_ARCH_386 ( 3 << 16) +#define KEXEC_ARCH_X86_64 (62 << 16) +#define KEXEC_ARCH_PPC (20 << 16) +#define KEXEC_ARCH_PPC64 (21 << 16) +#define KEXEC_ARCH_IA_64 (50 << 16) +#define KEXEC_ARCH_S390 (22 << 16) + +#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */ + +/* Location of a reserved region to hold the crash kernel. + */ +extern struct resource crashk_res; + +#else /* !CONFIG_KEXEC */ +struct pt_regs; +struct task_struct; +static inline void crash_kexec(struct pt_regs *regs) { } +static inline int kexec_should_crash(struct task_struct *p) { return 0; } +#endif /* CONFIG_KEXEC */ +#endif /* LINUX_KEXEC_H */ diff --git a/include/linux/list.h b/include/linux/list.h index 399b51d..aab2db2 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -185,7 +185,7 @@ static inline void list_del(struct list_head *entry) * list_for_each_entry_rcu(). * * Note that the caller is not permitted to immediately free - * the newly deleted entry. Instead, either synchronize_kernel() + * the newly deleted entry. Instead, either synchronize_rcu() * or call_rcu() must be used to defer freeing until an RCU * grace period has elapsed. */ diff --git a/include/linux/nvram.h b/include/linux/nvram.h index b031e41..9189829 100644 --- a/include/linux/nvram.h +++ b/include/linux/nvram.h @@ -20,8 +20,6 @@ extern void __nvram_write_byte(unsigned char c, int i); extern void nvram_write_byte(unsigned char c, int i); extern int __nvram_check_checksum(void); extern int nvram_check_checksum(void); -extern void __nvram_set_checksum(void); -extern void nvram_set_checksum(void); #endif #endif /* _LINUX_NVRAM_H */ diff --git a/include/linux/pm.h b/include/linux/pm.h index ed2b76e..1447932 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -103,7 +103,8 @@ extern int pm_active; /* * Register a device with power management */ -struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback); +struct pm_dev __deprecated * +pm_register(pm_dev_t type, unsigned long id, pm_callback callback); /* * Unregister a device with power management @@ -190,17 +191,18 @@ typedef u32 __bitwise pm_message_t; /* * There are 4 important states driver can be in: * ON -- driver is working - * FREEZE -- stop operations and apply whatever policy is applicable to a suspended driver - * of that class, freeze queues for block like IDE does, drop packets for - * ethernet, etc... stop DMA engine too etc... so a consistent image can be - * saved; but do not power any hardware down. - * SUSPEND - like FREEZE, but hardware is doing as much powersaving as possible. Roughly - * pci D3. + * FREEZE -- stop operations and apply whatever policy is applicable to a + * suspended driver of that class, freeze queues for block like IDE + * does, drop packets for ethernet, etc... stop DMA engine too etc... + * so a consistent image can be saved; but do not power any hardware + * down. + * SUSPEND - like FREEZE, but hardware is doing as much powersaving as + * possible. Roughly pci D3. * - * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3 (SUSPEND). - * We'll need to fix the drivers. So yes, putting 3 to all diferent defines is intentional, - * and will go away as soon as drivers are fixed. Also note that typedef is neccessary, - * we'll probably want to switch to + * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3 + * (SUSPEND). We'll need to fix the drivers. So yes, putting 3 to all different + * defines is intentional, and will go away as soon as drivers are fixed. Also + * note that typedef is neccessary, we'll probably want to switch to * typedef struct pm_message_t { int event; int flags; } pm_message_t * or something similar soon. */ @@ -222,11 +224,18 @@ struct dev_pm_info { extern void device_pm_set_parent(struct device * dev, struct device * parent); -extern int device_suspend(pm_message_t state); extern int device_power_down(pm_message_t state); extern void device_power_up(void); extern void device_resume(void); +#ifdef CONFIG_PM +extern int device_suspend(pm_message_t state); +#else +static inline int device_suspend(pm_message_t state) +{ + return 0; +} +#endif #endif /* __KERNEL__ */ diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 59e5052..0563581 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -74,6 +74,13 @@ struct kcore_list { size_t size; }; +struct vmcore { + struct list_head list; + unsigned long long paddr; + unsigned long size; + loff_t offset; +}; + #ifdef CONFIG_PROC_FS extern struct proc_dir_entry proc_root; diff --git a/include/linux/reboot.h b/include/linux/reboot.h index d60fafc..2d4dd23 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -51,6 +51,10 @@ extern void machine_restart(char *cmd); extern void machine_halt(void); extern void machine_power_off(void); +extern void machine_shutdown(void); +struct pt_regs; +extern void machine_crash_shutdown(struct pt_regs *); + #endif #endif /* _LINUX_REBOOT_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 2c69682..9530b19 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -368,6 +368,11 @@ struct signal_struct { #endif }; +/* Context switch must be unlocked if interrupts are to be enabled */ +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW +# define __ARCH_WANT_UNLOCKED_CTXSW +#endif + /* * Bits in flags field of signal_struct. */ @@ -460,10 +465,11 @@ enum idle_type #define SD_LOAD_BALANCE 1 /* Do load balancing on this domain. */ #define SD_BALANCE_NEWIDLE 2 /* Balance when about to become idle */ #define SD_BALANCE_EXEC 4 /* Balance on exec */ -#define SD_WAKE_IDLE 8 /* Wake to idle CPU on task wakeup */ -#define SD_WAKE_AFFINE 16 /* Wake task to waking CPU */ -#define SD_WAKE_BALANCE 32 /* Perform balancing at task wakeup */ -#define SD_SHARE_CPUPOWER 64 /* Domain members share cpu power */ +#define SD_BALANCE_FORK 8 /* Balance on fork, clone */ +#define SD_WAKE_IDLE 16 /* Wake to idle CPU on task wakeup */ +#define SD_WAKE_AFFINE 32 /* Wake task to waking CPU */ +#define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */ +#define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */ struct sched_group { struct sched_group *next; /* Must be a circular list */ @@ -488,6 +494,11 @@ struct sched_domain { unsigned long long cache_hot_time; /* Task considered cache hot (ns) */ unsigned int cache_nice_tries; /* Leave cache hot tasks for # tries */ unsigned int per_cpu_gain; /* CPU % gained by adding domain cpus */ + unsigned int busy_idx; + unsigned int idle_idx; + unsigned int newidle_idx; + unsigned int wake_idx; + unsigned int forkexec_idx; int flags; /* See SD_* */ /* Runtime fields. */ @@ -511,10 +522,16 @@ struct sched_domain { unsigned long alb_failed; unsigned long alb_pushed; - /* sched_balance_exec() stats */ - unsigned long sbe_attempts; + /* SD_BALANCE_EXEC stats */ + unsigned long sbe_cnt; + unsigned long sbe_balanced; unsigned long sbe_pushed; + /* SD_BALANCE_FORK stats */ + unsigned long sbf_cnt; + unsigned long sbf_balanced; + unsigned long sbf_pushed; + /* try_to_wake_up() stats */ unsigned long ttwu_wake_remote; unsigned long ttwu_move_affine; @@ -522,6 +539,8 @@ struct sched_domain { #endif }; +extern void partition_sched_domains(cpumask_t *partition1, + cpumask_t *partition2); #ifdef ARCH_HAS_SCHED_DOMAIN /* Useful helpers that arch setup code may use. Defined in kernel/sched.c */ extern cpumask_t cpu_isolated_map; @@ -582,6 +601,9 @@ struct task_struct { int lock_depth; /* BKL lock depth */ +#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) + int oncpu; +#endif int prio, static_prio; struct list_head run_list; prio_array_t *array; @@ -704,8 +726,6 @@ struct task_struct { spinlock_t alloc_lock; /* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */ spinlock_t proc_lock; -/* context-switch lock */ - spinlock_t switch_lock; /* journalling filesystem info */ void *journal_info; @@ -912,7 +932,7 @@ extern void FASTCALL(wake_up_new_task(struct task_struct * tsk, #else static inline void kick_process(struct task_struct *tsk) { } #endif -extern void FASTCALL(sched_fork(task_t * p)); +extern void FASTCALL(sched_fork(task_t * p, int clone_flags)); extern void FASTCALL(sched_exit(task_t * p)); extern int in_group_p(gid_t); @@ -1245,33 +1265,78 @@ extern void normalize_rt_tasks(void); #endif -/* try_to_freeze - * - * Checks whether we need to enter the refrigerator - * and returns 1 if we did so. - */ #ifdef CONFIG_PM -extern void refrigerator(unsigned long); +/* + * Check if a process has been frozen + */ +static inline int frozen(struct task_struct *p) +{ + return p->flags & PF_FROZEN; +} + +/* + * Check if there is a request to freeze a process + */ +static inline int freezing(struct task_struct *p) +{ + return p->flags & PF_FREEZE; +} + +/* + * Request that a process be frozen + * FIXME: SMP problem. We may not modify other process' flags! + */ +static inline void freeze(struct task_struct *p) +{ + p->flags |= PF_FREEZE; +} + +/* + * Wake up a frozen process + */ +static inline int thaw_process(struct task_struct *p) +{ + if (frozen(p)) { + p->flags &= ~PF_FROZEN; + wake_up_process(p); + return 1; + } + return 0; +} + +/* + * freezing is complete, mark process as frozen + */ +static inline void frozen_process(struct task_struct *p) +{ + p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN; +} + +extern void refrigerator(void); extern int freeze_processes(void); extern void thaw_processes(void); -static inline int try_to_freeze(unsigned long refrigerator_flags) +static inline int try_to_freeze(void) { - if (unlikely(current->flags & PF_FREEZE)) { - refrigerator(refrigerator_flags); + if (freezing(current)) { + refrigerator(); return 1; } else return 0; } #else -static inline void refrigerator(unsigned long flag) {} +static inline int frozen(struct task_struct *p) { return 0; } +static inline int freezing(struct task_struct *p) { return 0; } +static inline void freeze(struct task_struct *p) { BUG(); } +static inline int thaw_process(struct task_struct *p) { return 1; } +static inline void frozen_process(struct task_struct *p) { BUG(); } + +static inline void refrigerator(void) {} static inline int freeze_processes(void) { BUG(); return 0; } static inline void thaw_processes(void) {} -static inline int try_to_freeze(unsigned long refrigerator_flags) -{ - return 0; -} +static inline int try_to_freeze(void) { return 0; } + #endif /* CONFIG_PM */ #endif /* __KERNEL__ */ diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 2bf0d5f..f2e96fd 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -58,7 +58,7 @@ static inline int software_suspend(void) } #endif -#ifdef CONFIG_SMP +#ifdef CONFIG_SUSPEND_SMP extern void disable_nonboot_cpus(void); extern void enable_nonboot_cpus(void); #else diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index c39f6f7..52830b6 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -159,8 +159,9 @@ asmlinkage long sys_shutdown(int, int); asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user *arg); asmlinkage long sys_restart_syscall(void); -asmlinkage long sys_kexec_load(void *entry, unsigned long nr_segments, - struct kexec_segment *segments, unsigned long flags); +asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, + struct kexec_segment __user *segments, + unsigned long flags); asmlinkage long sys_exit(int error_code); asmlinkage void sys_exit_group(int error_code); diff --git a/include/linux/topology.h b/include/linux/topology.h index d70e897..0320225 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -89,6 +89,11 @@ .cache_hot_time = 0, \ .cache_nice_tries = 0, \ .per_cpu_gain = 25, \ + .busy_idx = 0, \ + .idle_idx = 0, \ + .newidle_idx = 1, \ + .wake_idx = 0, \ + .forkexec_idx = 0, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ @@ -115,12 +120,15 @@ .cache_hot_time = (5*1000000/2), \ .cache_nice_tries = 1, \ .per_cpu_gain = 100, \ + .busy_idx = 2, \ + .idle_idx = 1, \ + .newidle_idx = 2, \ + .wake_idx = 1, \ + .forkexec_idx = 1, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ - | SD_WAKE_AFFINE \ - | SD_WAKE_IDLE \ - | SD_WAKE_BALANCE, \ + | SD_WAKE_AFFINE, \ .last_balance = jiffies, \ .balance_interval = 1, \ .nr_balance_failed = 0, \ diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 07e7d31..4def882 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -41,7 +41,7 @@ static int __init do_linuxrc(void * shell) static void __init handle_initrd(void) { int error; - int i, pid; + int pid; real_root_dev = new_encode_dev(ROOT_DEV); create_dev("/dev/root.old", Root_RAM0, NULL); @@ -58,7 +58,7 @@ static void __init handle_initrd(void) pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { - while (pid != sys_wait4(-1, &i, 0, NULL)) + while (pid != sys_wait4(-1, NULL, 0, NULL)) yield(); } diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt new file mode 100644 index 0000000..0b46a5d --- /dev/null +++ b/kernel/Kconfig.preempt @@ -0,0 +1,65 @@ + +choice + prompt "Preemption Model" + default PREEMPT_NONE + +config PREEMPT_NONE + bool "No Forced Preemption (Server)" + help + This is the traditional Linux preemption model, geared towards + throughput. It will still provide good latencies most of the + time, but there are no guarantees and occasional longer delays + are possible. + + Select this option if you are building a kernel for a server or + scientific/computation system, or if you want to maximize the + raw processing power of the kernel, irrespective of scheduling + latencies. + +config PREEMPT_VOLUNTARY + bool "Voluntary Kernel Preemption (Desktop)" + help + This option reduces the latency of the kernel by adding more + "explicit preemption points" to the kernel code. These new + preemption points have been selected to reduce the maximum + latency of rescheduling, providing faster application reactions, + at the cost of slighly lower throughput. + + This allows reaction to interactive events by allowing a + low priority process to voluntarily preempt itself even if it + is in kernel mode executing a system call. This allows + applications to run more 'smoothly' even when the system is + under load. + + Select this if you are building a kernel for a desktop system. + +config PREEMPT + bool "Preemptible Kernel (Low-Latency Desktop)" + help + This option reduces the latency of the kernel by making + all kernel code (that is not executing in a critical section) + preemptible. This allows reaction to interactive events by + permitting a low priority process to be preempted involuntarily + even if it is in kernel mode executing a system call and would + otherwise not be about to reach a natural preemption point. + This allows applications to run more 'smoothly' even when the + system is under load, at the cost of slighly lower throughput + and a slight runtime overhead to kernel code. + + Select this if you are building a kernel for a desktop or + embedded system with latency requirements in the milliseconds + range. + +endchoice + +config PREEMPT_BKL + bool "Preempt The Big Kernel Lock" + depends on SMP || PREEMPT + default y + help + This option reduces the latency of the kernel by making the + big kernel lock preemptible. + + Say Y here if you are building a kernel for a desktop system. + Say N if you are unsure. + diff --git a/kernel/Makefile b/kernel/Makefile index b01d26f..cb05cd0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_PM) += power/ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o +obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_CPUSETS) += cpuset.o obj-$(CONFIG_IKCONFIG) += configs.o @@ -27,6 +28,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ +obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_SECCOMP) += seccomp.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) diff --git a/kernel/cpu.c b/kernel/cpu.c index 628f4cc..53d8263 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -63,19 +63,15 @@ static int take_cpu_down(void *unused) { int err; - /* Take offline: makes arch_cpu_down somewhat easier. */ - cpu_clear(smp_processor_id(), cpu_online_map); - /* Ensure this CPU doesn't handle any more interrupts. */ err = __cpu_disable(); if (err < 0) - cpu_set(smp_processor_id(), cpu_online_map); - else - /* Force idle task to run as soon as we yield: it should - immediately notice cpu is offline and die quickly. */ - sched_idle_next(); + return err; - return err; + /* Force idle task to run as soon as we yield: it should + immediately notice cpu is offline and die quickly. */ + sched_idle_next(); + return 0; } int cpu_down(unsigned int cpu) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 79dd929..984c0bf 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -595,10 +595,62 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) return 0; } +/* + * For a given cpuset cur, partition the system as follows + * a. All cpus in the parent cpuset's cpus_allowed that are not part of any + * exclusive child cpusets + * b. All cpus in the current cpuset's cpus_allowed that are not part of any + * exclusive child cpusets + * Build these two partitions by calling partition_sched_domains + * + * Call with cpuset_sem held. May nest a call to the + * lock_cpu_hotplug()/unlock_cpu_hotplug() pair. + */ +static void update_cpu_domains(struct cpuset *cur) +{ + struct cpuset *c, *par = cur->parent; + cpumask_t pspan, cspan; + + if (par == NULL || cpus_empty(cur->cpus_allowed)) + return; + + /* + * Get all cpus from parent's cpus_allowed not part of exclusive + * children + */ + pspan = par->cpus_allowed; + list_for_each_entry(c, &par->children, sibling) { + if (is_cpu_exclusive(c)) + cpus_andnot(pspan, pspan, c->cpus_allowed); + } + if (is_removed(cur) || !is_cpu_exclusive(cur)) { + cpus_or(pspan, pspan, cur->cpus_allowed); + if (cpus_equal(pspan, cur->cpus_allowed)) + return; + cspan = CPU_MASK_NONE; + } else { + if (cpus_empty(pspan)) + return; + cspan = cur->cpus_allowed; + /* + * Get all cpus from current cpuset's cpus_allowed not part + * of exclusive children + */ + list_for_each_entry(c, &cur->children, sibling) { + if (is_cpu_exclusive(c)) + cpus_andnot(cspan, cspan, c->cpus_allowed); + } + } + + lock_cpu_hotplug(); + partition_sched_domains(&pspan, &cspan); + unlock_cpu_hotplug(); +} + static int update_cpumask(struct cpuset *cs, char *buf) { struct cpuset trialcs; - int retval; + int retval, cpus_unchanged; trialcs = *cs; retval = cpulist_parse(buf, trialcs.cpus_allowed); @@ -608,9 +660,13 @@ static int update_cpumask(struct cpuset *cs, char *buf) if (cpus_empty(trialcs.cpus_allowed)) return -ENOSPC; retval = validate_change(cs, &trialcs); - if (retval == 0) - cs->cpus_allowed = trialcs.cpus_allowed; - return retval; + if (retval < 0) + return retval; + cpus_unchanged = cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed); + cs->cpus_allowed = trialcs.cpus_allowed; + if (is_cpu_exclusive(cs) && !cpus_unchanged) + update_cpu_domains(cs); + return 0; } static int update_nodemask(struct cpuset *cs, char *buf) @@ -646,7 +702,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) { int turning_on; struct cpuset trialcs; - int err; + int err, cpu_exclusive_changed; turning_on = (simple_strtoul(buf, NULL, 10) != 0); @@ -657,13 +713,18 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) clear_bit(bit, &trialcs.flags); err = validate_change(cs, &trialcs); - if (err == 0) { - if (turning_on) - set_bit(bit, &cs->flags); - else - clear_bit(bit, &cs->flags); - } - return err; + if (err < 0) + return err; + cpu_exclusive_changed = + (is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs)); + if (turning_on) + set_bit(bit, &cs->flags); + else + clear_bit(bit, &cs->flags); + + if (cpu_exclusive_changed) + update_cpu_domains(cs); + return 0; } static int attach_task(struct cpuset *cs, char *buf) @@ -1309,12 +1370,14 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) up(&cpuset_sem); return -EBUSY; } - spin_lock(&cs->dentry->d_lock); parent = cs->parent; set_bit(CS_REMOVED, &cs->flags); + if (is_cpu_exclusive(cs)) + update_cpu_domains(cs); list_del(&cs->sibling); /* delete my sibling from parent->children */ if (list_empty(&parent->children)) check_for_release(parent); + spin_lock(&cs->dentry->d_lock); d = dget(cs->dentry); cs->dentry = NULL; spin_unlock(&d->d_lock); diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c new file mode 100644 index 0000000..459ba49 --- /dev/null +++ b/kernel/crash_dump.c @@ -0,0 +1,52 @@ +/* + * kernel/crash_dump.c - Memory preserving reboot related code. + * + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * Copyright (C) IBM Corporation, 2004. All rights reserved + */ + +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/proc_fs.h> +#include <linux/bootmem.h> +#include <linux/highmem.h> +#include <linux/crash_dump.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +/* Stores the physical address of elf header of crash image. */ +unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; + +/* + * Copy a page from "oldmem". For this page, there is no pte mapped + * in the current kernel. We stitch up a pte, similar to kmap_atomic. + */ +ssize_t copy_oldmem_page(unsigned long pfn, char *buf, + size_t csize, unsigned long offset, int userbuf) +{ + void *page, *vaddr; + + if (!csize) + return 0; + + page = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!page) + return -ENOMEM; + + vaddr = kmap_atomic_pfn(pfn, KM_PTE0); + copy_page(page, vaddr); + kunmap_atomic(vaddr, KM_PTE0); + + if (userbuf) { + if (copy_to_user(buf, (page + offset), csize)) { + kfree(page); + return -EFAULT; + } + } else { + memcpy(buf, (page + offset), csize); + } + + kfree(page); + return csize; +} diff --git a/kernel/fork.c b/kernel/fork.c index a28d11e..2c78068 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1003,9 +1003,6 @@ static task_t *copy_process(unsigned long clone_flags, p->pdeath_signal = 0; p->exit_state = 0; - /* Perform scheduler related setup */ - sched_fork(p); - /* * Ok, make it visible to the rest of the system. * We dont wake it up yet. @@ -1014,18 +1011,24 @@ static task_t *copy_process(unsigned long clone_flags, INIT_LIST_HEAD(&p->ptrace_children); INIT_LIST_HEAD(&p->ptrace_list); + /* Perform scheduler related setup. Assign this task to a CPU. */ + sched_fork(p, clone_flags); + /* Need tasklist lock for parent etc handling! */ write_lock_irq(&tasklist_lock); /* - * The task hasn't been attached yet, so cpus_allowed mask cannot - * have changed. The cpus_allowed mask of the parent may have - * changed after it was copied first time, and it may then move to - * another CPU - so we re-copy it here and set the child's CPU to - * the parent's CPU. This avoids alot of nasty races. + * The task hasn't been attached yet, so its cpus_allowed mask will + * not be changed, nor will its assigned CPU. + * + * The cpus_allowed mask of the parent may have changed after it was + * copied first time - so re-copy it here, then check the child's CPU + * to ensure it is on a valid CPU (and if not, just force it back to + * parent's CPU). This avoids alot of nasty races. */ p->cpus_allowed = current->cpus_allowed; - set_task_cpu(p, smp_processor_id()); + if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed))) + set_task_cpu(p, smp_processor_id()); /* * Check for pending SIGKILL! The new thread should not be allowed diff --git a/kernel/kexec.c b/kernel/kexec.c new file mode 100644 index 0000000..7843548 --- /dev/null +++ b/kernel/kexec.c @@ -0,0 +1,1063 @@ +/* + * kexec.c - kexec system call + * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com> + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/mm.h> +#include <linux/file.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/kexec.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/highmem.h> +#include <linux/syscalls.h> +#include <linux/reboot.h> +#include <linux/syscalls.h> +#include <linux/ioport.h> +#include <linux/hardirq.h> + +#include <asm/page.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/semaphore.h> + +/* Location of the reserved area for the crash kernel */ +struct resource crashk_res = { + .name = "Crash kernel", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +int kexec_should_crash(struct task_struct *p) +{ + if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops) + return 1; + return 0; +} + +/* + * When kexec transitions to the new kernel there is a one-to-one + * mapping between physical and virtual addresses. On processors + * where you can disable the MMU this is trivial, and easy. For + * others it is still a simple predictable page table to setup. + * + * In that environment kexec copies the new kernel to its final + * resting place. This means I can only support memory whose + * physical address can fit in an unsigned long. In particular + * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled. + * If the assembly stub has more restrictive requirements + * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be + * defined more restrictively in <asm/kexec.h>. + * + * The code for the transition from the current kernel to the + * the new kernel is placed in the control_code_buffer, whose size + * is given by KEXEC_CONTROL_CODE_SIZE. In the best case only a single + * page of memory is necessary, but some architectures require more. + * Because this memory must be identity mapped in the transition from + * virtual to physical addresses it must live in the range + * 0 - TASK_SIZE, as only the user space mappings are arbitrarily + * modifiable. + * + * The assembly stub in the control code buffer is passed a linked list + * of descriptor pages detailing the source pages of the new kernel, + * and the destination addresses of those source pages. As this data + * structure is not used in the context of the current OS, it must + * be self-contained. + * + * The code has been made to work with highmem pages and will use a + * destination page in its final resting place (if it happens + * to allocate it). The end product of this is that most of the + * physical address space, and most of RAM can be used. + * + * Future directions include: + * - allocating a page table with the control code buffer identity + * mapped, to simplify machine_kexec and make kexec_on_panic more + * reliable. + */ + +/* + * KIMAGE_NO_DEST is an impossible destination address..., for + * allocating pages whose destination address we do not care about. + */ +#define KIMAGE_NO_DEST (-1UL) + +static int kimage_is_destination_range(struct kimage *image, + unsigned long start, unsigned long end); +static struct page *kimage_alloc_page(struct kimage *image, + unsigned int gfp_mask, + unsigned long dest); + +static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments) +{ + size_t segment_bytes; + struct kimage *image; + unsigned long i; + int result; + + /* Allocate a controlling structure */ + result = -ENOMEM; + image = kmalloc(sizeof(*image), GFP_KERNEL); + if (!image) + goto out; + + memset(image, 0, sizeof(*image)); + image->head = 0; + image->entry = &image->head; + image->last_entry = &image->head; + image->control_page = ~0; /* By default this does not apply */ + image->start = entry; + image->type = KEXEC_TYPE_DEFAULT; + + /* Initialize the list of control pages */ + INIT_LIST_HEAD(&image->control_pages); + + /* Initialize the list of destination pages */ + INIT_LIST_HEAD(&image->dest_pages); + + /* Initialize the list of unuseable pages */ + INIT_LIST_HEAD(&image->unuseable_pages); + + /* Read in the segments */ + image->nr_segments = nr_segments; + segment_bytes = nr_segments * sizeof(*segments); + result = copy_from_user(image->segment, segments, segment_bytes); + if (result) + goto out; + + /* + * Verify we have good destination addresses. The caller is + * responsible for making certain we don't attempt to load + * the new image into invalid or reserved areas of RAM. This + * just verifies it is an address we can use. + * + * Since the kernel does everything in page size chunks ensure + * the destination addreses are page aligned. Too many + * special cases crop of when we don't do this. The most + * insidious is getting overlapping destination addresses + * simply because addresses are changed to page size + * granularity. + */ + result = -EADDRNOTAVAIL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK)) + goto out; + if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT) + goto out; + } + + /* Verify our destination addresses do not overlap. + * If we alloed overlapping destination addresses + * through very weird things can happen with no + * easy explanation as one segment stops on another. + */ + result = -EINVAL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + unsigned long j; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + for (j = 0; j < i; j++) { + unsigned long pstart, pend; + pstart = image->segment[j].mem; + pend = pstart + image->segment[j].memsz; + /* Do the segments overlap ? */ + if ((mend > pstart) && (mstart < pend)) + goto out; + } + } + + /* Ensure our buffer sizes are strictly less than + * our memory sizes. This should always be the case, + * and it is easier to check up front than to be surprised + * later on. + */ + result = -EINVAL; + for (i = 0; i < nr_segments; i++) { + if (image->segment[i].bufsz > image->segment[i].memsz) + goto out; + } + + result = 0; +out: + if (result == 0) + *rimage = image; + else + kfree(image); + + return result; + +} + +static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments) +{ + int result; + struct kimage *image; + + /* Allocate and initialize a controlling structure */ + image = NULL; + result = do_kimage_alloc(&image, entry, nr_segments, segments); + if (result) + goto out; + + *rimage = image; + + /* + * Find a location for the control code buffer, and add it + * the vector of segments so that it's pages will also be + * counted as destination pages. + */ + result = -ENOMEM; + image->control_code_page = kimage_alloc_control_pages(image, + get_order(KEXEC_CONTROL_CODE_SIZE)); + if (!image->control_code_page) { + printk(KERN_ERR "Could not allocate control_code_buffer\n"); + goto out; + } + + result = 0; + out: + if (result == 0) + *rimage = image; + else + kfree(image); + + return result; +} + +static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, + unsigned long nr_segments, + struct kexec_segment *segments) +{ + int result; + struct kimage *image; + unsigned long i; + + image = NULL; + /* Verify we have a valid entry point */ + if ((entry < crashk_res.start) || (entry > crashk_res.end)) { + result = -EADDRNOTAVAIL; + goto out; + } + + /* Allocate and initialize a controlling structure */ + result = do_kimage_alloc(&image, entry, nr_segments, segments); + if (result) + goto out; + + /* Enable the special crash kernel control page + * allocation policy. + */ + image->control_page = crashk_res.start; + image->type = KEXEC_TYPE_CRASH; + + /* + * Verify we have good destination addresses. Normally + * the caller is responsible for making certain we don't + * attempt to load the new image into invalid or reserved + * areas of RAM. But crash kernels are preloaded into a + * reserved area of ram. We must ensure the addresses + * are in the reserved area otherwise preloading the + * kernel could corrupt things. + */ + result = -EADDRNOTAVAIL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz - 1; + /* Ensure we are within the crash kernel limits */ + if ((mstart < crashk_res.start) || (mend > crashk_res.end)) + goto out; + } + + /* + * Find a location for the control code buffer, and add + * the vector of segments so that it's pages will also be + * counted as destination pages. + */ + result = -ENOMEM; + image->control_code_page = kimage_alloc_control_pages(image, + get_order(KEXEC_CONTROL_CODE_SIZE)); + if (!image->control_code_page) { + printk(KERN_ERR "Could not allocate control_code_buffer\n"); + goto out; + } + + result = 0; +out: + if (result == 0) + *rimage = image; + else + kfree(image); + + return result; +} + +static int kimage_is_destination_range(struct kimage *image, + unsigned long start, + unsigned long end) +{ + unsigned long i; + + for (i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((end > mstart) && (start < mend)) + return 1; + } + + return 0; +} + +static struct page *kimage_alloc_pages(unsigned int gfp_mask, + unsigned int order) +{ + struct page *pages; + + pages = alloc_pages(gfp_mask, order); + if (pages) { + unsigned int count, i; + pages->mapping = NULL; + pages->private = order; + count = 1 << order; + for (i = 0; i < count; i++) + SetPageReserved(pages + i); + } + + return pages; +} + +static void kimage_free_pages(struct page *page) +{ + unsigned int order, count, i; + + order = page->private; + count = 1 << order; + for (i = 0; i < count; i++) + ClearPageReserved(page + i); + __free_pages(page, order); +} + +static void kimage_free_page_list(struct list_head *list) +{ + struct list_head *pos, *next; + + list_for_each_safe(pos, next, list) { + struct page *page; + + page = list_entry(pos, struct page, lru); + list_del(&page->lru); + kimage_free_pages(page); + } +} + +static struct page *kimage_alloc_normal_control_pages(struct kimage *image, + unsigned int order) +{ + /* Control pages are special, they are the intermediaries + * that are needed while we copy the rest of the pages + * to their final resting place. As such they must + * not conflict with either the destination addresses + * or memory the kernel is already using. + * + * The only case where we really need more than one of + * these are for architectures where we cannot disable + * the MMU and must instead generate an identity mapped + * page table for all of the memory. + * + * At worst this runs in O(N) of the image size. + */ + struct list_head extra_pages; + struct page *pages; + unsigned int count; + + count = 1 << order; + INIT_LIST_HEAD(&extra_pages); + + /* Loop while I can allocate a page and the page allocated + * is a destination page. + */ + do { + unsigned long pfn, epfn, addr, eaddr; + + pages = kimage_alloc_pages(GFP_KERNEL, order); + if (!pages) + break; + pfn = page_to_pfn(pages); + epfn = pfn + count; + addr = pfn << PAGE_SHIFT; + eaddr = epfn << PAGE_SHIFT; + if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) || + kimage_is_destination_range(image, addr, eaddr)) { + list_add(&pages->lru, &extra_pages); + pages = NULL; + } + } while (!pages); + + if (pages) { + /* Remember the allocated page... */ + list_add(&pages->lru, &image->control_pages); + + /* Because the page is already in it's destination + * location we will never allocate another page at + * that address. Therefore kimage_alloc_pages + * will not return it (again) and we don't need + * to give it an entry in image->segment[]. + */ + } + /* Deal with the destination pages I have inadvertently allocated. + * + * Ideally I would convert multi-page allocations into single + * page allocations, and add everyting to image->dest_pages. + * + * For now it is simpler to just free the pages. + */ + kimage_free_page_list(&extra_pages); + + return pages; +} + +static struct page *kimage_alloc_crash_control_pages(struct kimage *image, + unsigned int order) +{ + /* Control pages are special, they are the intermediaries + * that are needed while we copy the rest of the pages + * to their final resting place. As such they must + * not conflict with either the destination addresses + * or memory the kernel is already using. + * + * Control pages are also the only pags we must allocate + * when loading a crash kernel. All of the other pages + * are specified by the segments and we just memcpy + * into them directly. + * + * The only case where we really need more than one of + * these are for architectures where we cannot disable + * the MMU and must instead generate an identity mapped + * page table for all of the memory. + * + * Given the low demand this implements a very simple + * allocator that finds the first hole of the appropriate + * size in the reserved memory region, and allocates all + * of the memory up to and including the hole. + */ + unsigned long hole_start, hole_end, size; + struct page *pages; + + pages = NULL; + size = (1 << order) << PAGE_SHIFT; + hole_start = (image->control_page + (size - 1)) & ~(size - 1); + hole_end = hole_start + size - 1; + while (hole_end <= crashk_res.end) { + unsigned long i; + + if (hole_end > KEXEC_CONTROL_MEMORY_LIMIT) + break; + if (hole_end > crashk_res.end) + break; + /* See if I overlap any of the segments */ + for (i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz - 1; + if ((hole_end >= mstart) && (hole_start <= mend)) { + /* Advance the hole to the end of the segment */ + hole_start = (mend + (size - 1)) & ~(size - 1); + hole_end = hole_start + size - 1; + break; + } + } + /* If I don't overlap any segments I have found my hole! */ + if (i == image->nr_segments) { + pages = pfn_to_page(hole_start >> PAGE_SHIFT); + break; + } + } + if (pages) + image->control_page = hole_end; + + return pages; +} + + +struct page *kimage_alloc_control_pages(struct kimage *image, + unsigned int order) +{ + struct page *pages = NULL; + + switch (image->type) { + case KEXEC_TYPE_DEFAULT: + pages = kimage_alloc_normal_control_pages(image, order); + break; + case KEXEC_TYPE_CRASH: + pages = kimage_alloc_crash_control_pages(image, order); + break; + } + + return pages; +} + +static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) +{ + if (*image->entry != 0) + image->entry++; + + if (image->entry == image->last_entry) { + kimage_entry_t *ind_page; + struct page *page; + + page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST); + if (!page) + return -ENOMEM; + + ind_page = page_address(page); + *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; + image->entry = ind_page; + image->last_entry = ind_page + + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); + } + *image->entry = entry; + image->entry++; + *image->entry = 0; + + return 0; +} + +static int kimage_set_destination(struct kimage *image, + unsigned long destination) +{ + int result; + + destination &= PAGE_MASK; + result = kimage_add_entry(image, destination | IND_DESTINATION); + if (result == 0) + image->destination = destination; + + return result; +} + + +static int kimage_add_page(struct kimage *image, unsigned long page) +{ + int result; + + page &= PAGE_MASK; + result = kimage_add_entry(image, page | IND_SOURCE); + if (result == 0) + image->destination += PAGE_SIZE; + + return result; +} + + +static void kimage_free_extra_pages(struct kimage *image) +{ + /* Walk through and free any extra destination pages I may have */ + kimage_free_page_list(&image->dest_pages); + + /* Walk through and free any unuseable pages I have cached */ + kimage_free_page_list(&image->unuseable_pages); + +} +static int kimage_terminate(struct kimage *image) +{ + if (*image->entry != 0) + image->entry++; + + *image->entry = IND_DONE; + + return 0; +} + +#define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION)? \ + phys_to_virt((entry & PAGE_MASK)): ptr +1) + +static void kimage_free_entry(kimage_entry_t entry) +{ + struct page *page; + + page = pfn_to_page(entry >> PAGE_SHIFT); + kimage_free_pages(page); +} + +static void kimage_free(struct kimage *image) +{ + kimage_entry_t *ptr, entry; + kimage_entry_t ind = 0; + + if (!image) + return; + + kimage_free_extra_pages(image); + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_INDIRECTION) { + /* Free the previous indirection page */ + if (ind & IND_INDIRECTION) + kimage_free_entry(ind); + /* Save this indirection page until we are + * done with it. + */ + ind = entry; + } + else if (entry & IND_SOURCE) + kimage_free_entry(entry); + } + /* Free the final indirection page */ + if (ind & IND_INDIRECTION) + kimage_free_entry(ind); + + /* Handle any machine specific cleanup */ + machine_kexec_cleanup(image); + + /* Free the kexec control pages... */ + kimage_free_page_list(&image->control_pages); + kfree(image); +} + +static kimage_entry_t *kimage_dst_used(struct kimage *image, + unsigned long page) +{ + kimage_entry_t *ptr, entry; + unsigned long destination = 0; + + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_DESTINATION) + destination = entry & PAGE_MASK; + else if (entry & IND_SOURCE) { + if (page == destination) + return ptr; + destination += PAGE_SIZE; + } + } + + return 0; +} + +static struct page *kimage_alloc_page(struct kimage *image, + unsigned int gfp_mask, + unsigned long destination) +{ + /* + * Here we implement safeguards to ensure that a source page + * is not copied to its destination page before the data on + * the destination page is no longer useful. + * + * To do this we maintain the invariant that a source page is + * either its own destination page, or it is not a + * destination page at all. + * + * That is slightly stronger than required, but the proof + * that no problems will not occur is trivial, and the + * implementation is simply to verify. + * + * When allocating all pages normally this algorithm will run + * in O(N) time, but in the worst case it will run in O(N^2) + * time. If the runtime is a problem the data structures can + * be fixed. + */ + struct page *page; + unsigned long addr; + + /* + * Walk through the list of destination pages, and see if I + * have a match. + */ + list_for_each_entry(page, &image->dest_pages, lru) { + addr = page_to_pfn(page) << PAGE_SHIFT; + if (addr == destination) { + list_del(&page->lru); + return page; + } + } + page = NULL; + while (1) { + kimage_entry_t *old; + + /* Allocate a page, if we run out of memory give up */ + page = kimage_alloc_pages(gfp_mask, 0); + if (!page) + return 0; + /* If the page cannot be used file it away */ + if (page_to_pfn(page) > + (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { + list_add(&page->lru, &image->unuseable_pages); + continue; + } + addr = page_to_pfn(page) << PAGE_SHIFT; + + /* If it is the destination page we want use it */ + if (addr == destination) + break; + + /* If the page is not a destination page use it */ + if (!kimage_is_destination_range(image, addr, + addr + PAGE_SIZE)) + break; + + /* + * I know that the page is someones destination page. + * See if there is already a source page for this + * destination page. And if so swap the source pages. + */ + old = kimage_dst_used(image, addr); + if (old) { + /* If so move it */ + unsigned long old_addr; + struct page *old_page; + + old_addr = *old & PAGE_MASK; + old_page = pfn_to_page(old_addr >> PAGE_SHIFT); + copy_highpage(page, old_page); + *old = addr | (*old & ~PAGE_MASK); + + /* The old page I have found cannot be a + * destination page, so return it. + */ + addr = old_addr; + page = old_page; + break; + } + else { + /* Place the page on the destination list I + * will use it later. + */ + list_add(&page->lru, &image->dest_pages); + } + } + + return page; +} + +static int kimage_load_normal_segment(struct kimage *image, + struct kexec_segment *segment) +{ + unsigned long maddr; + unsigned long ubytes, mbytes; + int result; + unsigned char *buf; + + result = 0; + buf = segment->buf; + ubytes = segment->bufsz; + mbytes = segment->memsz; + maddr = segment->mem; + + result = kimage_set_destination(image, maddr); + if (result < 0) + goto out; + + while (mbytes) { + struct page *page; + char *ptr; + size_t uchunk, mchunk; + + page = kimage_alloc_page(image, GFP_HIGHUSER, maddr); + if (page == 0) { + result = -ENOMEM; + goto out; + } + result = kimage_add_page(image, page_to_pfn(page) + << PAGE_SHIFT); + if (result < 0) + goto out; + + ptr = kmap(page); + /* Start with a clear page */ + memset(ptr, 0, PAGE_SIZE); + ptr += maddr & ~PAGE_MASK; + mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); + if (mchunk > mbytes) + mchunk = mbytes; + + uchunk = mchunk; + if (uchunk > ubytes) + uchunk = ubytes; + + result = copy_from_user(ptr, buf, uchunk); + kunmap(page); + if (result) { + result = (result < 0) ? result : -EIO; + goto out; + } + ubytes -= uchunk; + maddr += mchunk; + buf += mchunk; + mbytes -= mchunk; + } +out: + return result; +} + +static int kimage_load_crash_segment(struct kimage *image, + struct kexec_segment *segment) +{ + /* For crash dumps kernels we simply copy the data from + * user space to it's destination. + * We do things a page at a time for the sake of kmap. + */ + unsigned long maddr; + unsigned long ubytes, mbytes; + int result; + unsigned char *buf; + + result = 0; + buf = segment->buf; + ubytes = segment->bufsz; + mbytes = segment->memsz; + maddr = segment->mem; + while (mbytes) { + struct page *page; + char *ptr; + size_t uchunk, mchunk; + + page = pfn_to_page(maddr >> PAGE_SHIFT); + if (page == 0) { + result = -ENOMEM; + goto out; + } + ptr = kmap(page); + ptr += maddr & ~PAGE_MASK; + mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); + if (mchunk > mbytes) + mchunk = mbytes; + + uchunk = mchunk; + if (uchunk > ubytes) { + uchunk = ubytes; + /* Zero the trailing part of the page */ + memset(ptr + uchunk, 0, mchunk - uchunk); + } + result = copy_from_user(ptr, buf, uchunk); + kunmap(page); + if (result) { + result = (result < 0) ? result : -EIO; + goto out; + } + ubytes -= uchunk; + maddr += mchunk; + buf += mchunk; + mbytes -= mchunk; + } +out: + return result; +} + +static int kimage_load_segment(struct kimage *image, + struct kexec_segment *segment) +{ + int result = -ENOMEM; + + switch (image->type) { + case KEXEC_TYPE_DEFAULT: + result = kimage_load_normal_segment(image, segment); + break; + case KEXEC_TYPE_CRASH: + result = kimage_load_crash_segment(image, segment); + break; + } + + return result; +} + +/* + * Exec Kernel system call: for obvious reasons only root may call it. + * + * This call breaks up into three pieces. + * - A generic part which loads the new kernel from the current + * address space, and very carefully places the data in the + * allocated pages. + * + * - A generic part that interacts with the kernel and tells all of + * the devices to shut down. Preventing on-going dmas, and placing + * the devices in a consistent state so a later kernel can + * reinitialize them. + * + * - A machine specific part that includes the syscall number + * and the copies the image to it's final destination. And + * jumps into the image at entry. + * + * kexec does not sync, or unmount filesystems so if you need + * that to happen you need to do that yourself. + */ +struct kimage *kexec_image = NULL; +static struct kimage *kexec_crash_image = NULL; +/* + * A home grown binary mutex. + * Nothing can wait so this mutex is safe to use + * in interrupt context :) + */ +static int kexec_lock = 0; + +asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, + struct kexec_segment __user *segments, + unsigned long flags) +{ + struct kimage **dest_image, *image; + int locked; + int result; + + /* We only trust the superuser with rebooting the system. */ + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + /* + * Verify we have a legal set of flags + * This leaves us room for future extensions. + */ + if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK)) + return -EINVAL; + + /* Verify we are on the appropriate architecture */ + if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) && + ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT)) + return -EINVAL; + + /* Put an artificial cap on the number + * of segments passed to kexec_load. + */ + if (nr_segments > KEXEC_SEGMENT_MAX) + return -EINVAL; + + image = NULL; + result = 0; + + /* Because we write directly to the reserved memory + * region when loading crash kernels we need a mutex here to + * prevent multiple crash kernels from attempting to load + * simultaneously, and to prevent a crash kernel from loading + * over the top of a in use crash kernel. + * + * KISS: always take the mutex. + */ + locked = xchg(&kexec_lock, 1); + if (locked) + return -EBUSY; + + dest_image = &kexec_image; + if (flags & KEXEC_ON_CRASH) + dest_image = &kexec_crash_image; + if (nr_segments > 0) { + unsigned long i; + + /* Loading another kernel to reboot into */ + if ((flags & KEXEC_ON_CRASH) == 0) + result = kimage_normal_alloc(&image, entry, + nr_segments, segments); + /* Loading another kernel to switch to if this one crashes */ + else if (flags & KEXEC_ON_CRASH) { + /* Free any current crash dump kernel before + * we corrupt it. + */ + kimage_free(xchg(&kexec_crash_image, NULL)); + result = kimage_crash_alloc(&image, entry, + nr_segments, segments); + } + if (result) + goto out; + + result = machine_kexec_prepare(image); + if (result) + goto out; + + for (i = 0; i < nr_segments; i++) { + result = kimage_load_segment(image, &image->segment[i]); + if (result) + goto out; + } + result = kimage_terminate(image); + if (result) + goto out; + } + /* Install the new kernel, and Uninstall the old */ + image = xchg(dest_image, image); + +out: + xchg(&kexec_lock, 0); /* Release the mutex */ + kimage_free(image); + + return result; +} + +#ifdef CONFIG_COMPAT +asmlinkage long compat_sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct compat_kexec_segment __user *segments, + unsigned long flags) +{ + struct compat_kexec_segment in; + struct kexec_segment out, __user *ksegments; + unsigned long i, result; + + /* Don't allow clients that don't understand the native + * architecture to do anything. + */ + if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT) + return -EINVAL; + + if (nr_segments > KEXEC_SEGMENT_MAX) + return -EINVAL; + + ksegments = compat_alloc_user_space(nr_segments * sizeof(out)); + for (i=0; i < nr_segments; i++) { + result = copy_from_user(&in, &segments[i], sizeof(in)); + if (result) + return -EFAULT; + + out.buf = compat_ptr(in.buf); + out.bufsz = in.bufsz; + out.mem = in.mem; + out.memsz = in.memsz; + + result = copy_to_user(&ksegments[i], &out, sizeof(out)); + if (result) + return -EFAULT; + } + + return sys_kexec_load(entry, nr_segments, ksegments, flags); +} +#endif + +void crash_kexec(struct pt_regs *regs) +{ + struct kimage *image; + int locked; + + + /* Take the kexec_lock here to prevent sys_kexec_load + * running on one cpu from replacing the crash kernel + * we are using after a panic on a different cpu. + * + * If the crash kernel was not located in a fixed area + * of memory the xchg(&kexec_crash_image) would be + * sufficient. But since I reuse the memory... + */ + locked = xchg(&kexec_lock, 1); + if (!locked) { + image = xchg(&kexec_crash_image, NULL); + if (image) { + machine_crash_shutdown(regs); + machine_kexec(image); + } + xchg(&kexec_lock, 0); + } +} diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 1f064a6..015fb69 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -30,6 +30,16 @@ static ssize_t hotplug_seqnum_show(struct subsystem *subsys, char *page) KERNEL_ATTR_RO(hotplug_seqnum); #endif +#ifdef CONFIG_KEXEC +#include <asm/kexec.h> + +static ssize_t crash_notes_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%p\n", (void *)crash_notes); +} +KERNEL_ATTR_RO(crash_notes); +#endif + decl_subsys(kernel, NULL, NULL); EXPORT_SYMBOL_GPL(kernel_subsys); @@ -37,6 +47,9 @@ static struct attribute * kernel_attrs[] = { #ifdef CONFIG_HOTPLUG &hotplug_seqnum_attr.attr, #endif +#ifdef CONFIG_KEXEC + &crash_notes_attr.attr, +#endif NULL }; diff --git a/kernel/panic.c b/kernel/panic.c index 081f746..74ba5f3 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -18,6 +18,7 @@ #include <linux/sysrq.h> #include <linux/interrupt.h> #include <linux/nmi.h> +#include <linux/kexec.h> int panic_timeout; int panic_on_oops; @@ -63,6 +64,13 @@ NORET_TYPE void panic(const char * fmt, ...) unsigned long caller = (unsigned long) __builtin_return_address(0); #endif + /* + * It's possible to come here directly from a panic-assertion and not + * have preempt disabled. Some functions called from here want + * preempt to be disabled. No point enabling it later though... + */ + preempt_disable(); + bust_spinlocks(1); va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); @@ -70,7 +78,19 @@ NORET_TYPE void panic(const char * fmt, ...) printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf); bust_spinlocks(0); + /* + * If we have crashed and we have a crash kernel loaded let it handle + * everything else. + * Do we want to call this before we try to display a message? + */ + crash_kexec(NULL); + #ifdef CONFIG_SMP + /* + * Note smp_send_stop is the usual smp shutdown function, which + * unfortunately means it may not be hardened to work in a panic + * situation. + */ smp_send_stop(); #endif @@ -79,8 +99,7 @@ NORET_TYPE void panic(const char * fmt, ...) if (!panic_blink) panic_blink = no_blink; - if (panic_timeout > 0) - { + if (panic_timeout > 0) { /* * Delay timeout seconds before rebooting the machine. * We can't use the "normal" timers since we just panicked.. diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 696387f..2c7121d 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -27,8 +27,8 @@ config PM_DEBUG like suspend support. config SOFTWARE_SUSPEND - bool "Software Suspend (EXPERIMENTAL)" - depends on EXPERIMENTAL && PM && SWAP + bool "Software Suspend" + depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP)) ---help--- Enable the possibility of suspending the machine. It doesn't need APM. @@ -72,3 +72,7 @@ config PM_STD_PARTITION suspended image to. It will simply pick the first available swap device. +config SUSPEND_SMP + bool + depends on HOTPLUG_CPU && X86 && PM + default y diff --git a/kernel/power/Makefile b/kernel/power/Makefile index fbdc634..2f438d0 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -3,9 +3,9 @@ ifeq ($(CONFIG_PM_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif -swsusp-smp-$(CONFIG_SMP) += smp.o - obj-y := main.o process.o console.o pm.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y) disk.o +obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o + +obj-$(CONFIG_SUSPEND_SMP) += smp.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 02b6764..fb8de63 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -117,8 +117,8 @@ static void finish(void) { device_resume(); platform_finish(); - enable_nonboot_cpus(); thaw_processes(); + enable_nonboot_cpus(); pm_restore_console(); } @@ -131,28 +131,35 @@ static int prepare_processes(void) sys_sync(); + disable_nonboot_cpus(); + if (freeze_processes()) { error = -EBUSY; - return error; + goto thaw; } if (pm_disk_mode == PM_DISK_PLATFORM) { if (pm_ops && pm_ops->prepare) { if ((error = pm_ops->prepare(PM_SUSPEND_DISK))) - return error; + goto thaw; } } /* Free memory before shutting down devices. */ free_some_memory(); - return 0; +thaw: + thaw_processes(); + enable_nonboot_cpus(); + pm_restore_console(); + return error; } static void unprepare_processes(void) { - enable_nonboot_cpus(); + platform_finish(); thaw_processes(); + enable_nonboot_cpus(); pm_restore_console(); } @@ -160,15 +167,9 @@ static int prepare_devices(void) { int error; - disable_nonboot_cpus(); - if ((error = device_suspend(PMSG_FREEZE))) { + if ((error = device_suspend(PMSG_FREEZE))) printk("Some devices failed to suspend\n"); - platform_finish(); - enable_nonboot_cpus(); - return error; - } - - return 0; + return error; } /** @@ -185,9 +186,9 @@ int pm_suspend_disk(void) int error; error = prepare_processes(); - if (!error) { - error = prepare_devices(); - } + if (error) + return error; + error = prepare_devices(); if (error) { unprepare_processes(); @@ -250,7 +251,7 @@ static int software_resume(void) if ((error = prepare_processes())) { swsusp_close(); - goto Cleanup; + goto Done; } pr_debug("PM: Reading swsusp image.\n"); diff --git a/kernel/power/main.c b/kernel/power/main.c index 4cdebc9..c94cb9e 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -55,6 +55,13 @@ static int suspend_prepare(suspend_state_t state) pm_prepare_console(); + disable_nonboot_cpus(); + + if (num_online_cpus() != 1) { + error = -EPERM; + goto Enable_cpu; + } + if (freeze_processes()) { error = -EAGAIN; goto Thaw; @@ -75,6 +82,8 @@ static int suspend_prepare(suspend_state_t state) pm_ops->finish(state); Thaw: thaw_processes(); + Enable_cpu: + enable_nonboot_cpus(); pm_restore_console(); return error; } @@ -113,6 +122,7 @@ static void suspend_finish(suspend_state_t state) if (pm_ops && pm_ops->finish) pm_ops->finish(state); thaw_processes(); + enable_nonboot_cpus(); pm_restore_console(); } @@ -150,12 +160,6 @@ static int enter_state(suspend_state_t state) goto Unlock; } - /* Suspend is hard to get right on SMP. */ - if (num_online_cpus() != 1) { - error = -EPERM; - goto Unlock; - } - pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); if ((error = suspend_prepare(state))) goto Unlock; diff --git a/kernel/power/process.c b/kernel/power/process.c index 78d92dc..0a08664 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -32,7 +32,7 @@ static inline int freezeable(struct task_struct * p) } /* Refrigerator is place where frozen processes are stored :-). */ -void refrigerator(unsigned long flag) +void refrigerator(void) { /* Hmm, should we be allowed to suspend when there are realtime processes around? */ @@ -41,14 +41,13 @@ void refrigerator(unsigned long flag) current->state = TASK_UNINTERRUPTIBLE; pr_debug("%s entered refrigerator\n", current->comm); printk("="); - current->flags &= ~PF_FREEZE; + frozen_process(current); spin_lock_irq(¤t->sighand->siglock); recalc_sigpending(); /* We sent fake signal, clean it up */ spin_unlock_irq(¤t->sighand->siglock); - current->flags |= PF_FROZEN; - while (current->flags & PF_FROZEN) + while (frozen(current)) schedule(); pr_debug("%s left refrigerator\n", current->comm); current->state = save; @@ -57,10 +56,10 @@ void refrigerator(unsigned long flag) /* 0 = success, else # of processes that we failed to stop */ int freeze_processes(void) { - int todo; - unsigned long start_time; + int todo; + unsigned long start_time; struct task_struct *g, *p; - + printk( "Stopping tasks: " ); start_time = jiffies; do { @@ -70,14 +69,12 @@ int freeze_processes(void) unsigned long flags; if (!freezeable(p)) continue; - if ((p->flags & PF_FROZEN) || + if ((frozen(p)) || (p->state == TASK_TRACED) || (p->state == TASK_STOPPED)) continue; - /* FIXME: smp problem here: we may not access other process' flags - without locking */ - p->flags |= PF_FREEZE; + freeze(p); spin_lock_irqsave(&p->sighand->siglock, flags); signal_wake_up(p, 0); spin_unlock_irqrestore(&p->sighand->siglock, flags); @@ -91,7 +88,7 @@ int freeze_processes(void) return todo; } } while(todo); - + printk( "|\n" ); BUG_ON(in_atomic()); return 0; @@ -106,10 +103,7 @@ void thaw_processes(void) do_each_thread(g, p) { if (!freezeable(p)) continue; - if (p->flags & PF_FROZEN) { - p->flags &= ~PF_FROZEN; - wake_up_process(p); - } else + if (!thaw_process(p)) printk(KERN_INFO " Strange, %s not stopped\n", p->comm ); } while_each_thread(g, p); diff --git a/kernel/power/smp.c b/kernel/power/smp.c index 457c230..bbe2307 100644 --- a/kernel/power/smp.c +++ b/kernel/power/smp.c @@ -13,73 +13,52 @@ #include <linux/interrupt.h> #include <linux/suspend.h> #include <linux/module.h> +#include <linux/cpu.h> #include <asm/atomic.h> #include <asm/tlbflush.h> -static atomic_t cpu_counter, freeze; - - -static void smp_pause(void * data) -{ - struct saved_context ctxt; - __save_processor_state(&ctxt); - printk("Sleeping in:\n"); - dump_stack(); - atomic_inc(&cpu_counter); - while (atomic_read(&freeze)) { - /* FIXME: restore takes place at random piece inside this. - This should probably be written in assembly, and - preserve general-purpose registers, too - - What about stack? We may need to move to new stack here. - - This should better be ran with interrupts disabled. - */ - cpu_relax(); - barrier(); - } - atomic_dec(&cpu_counter); - __restore_processor_state(&ctxt); -} - -static cpumask_t oldmask; +/* This is protected by pm_sem semaphore */ +static cpumask_t frozen_cpus; void disable_nonboot_cpus(void) { - oldmask = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(0)); - printk("Freezing CPUs (at %d)", raw_smp_processor_id()); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ); - printk("..."); - BUG_ON(raw_smp_processor_id() != 0); - - /* FIXME: for this to work, all the CPUs must be running - * "idle" thread (or we deadlock). Is that guaranteed? */ + int cpu, error; - atomic_set(&cpu_counter, 0); - atomic_set(&freeze, 1); - smp_call_function(smp_pause, NULL, 0, 0); - while (atomic_read(&cpu_counter) < (num_online_cpus() - 1)) { - cpu_relax(); - barrier(); + error = 0; + cpus_clear(frozen_cpus); + printk("Freezing cpus ...\n"); + for_each_online_cpu(cpu) { + if (cpu == 0) + continue; + error = cpu_down(cpu); + if (!error) { + cpu_set(cpu, frozen_cpus); + printk("CPU%d is down\n", cpu); + continue; + } + printk("Error taking cpu %d down: %d\n", cpu, error); } - printk("ok\n"); + BUG_ON(smp_processor_id() != 0); + if (error) + panic("cpus not sleeping"); } void enable_nonboot_cpus(void) { - printk("Restarting CPUs"); - atomic_set(&freeze, 0); - while (atomic_read(&cpu_counter)) { - cpu_relax(); - barrier(); - } - printk("..."); - set_cpus_allowed(current, oldmask); - schedule(); - printk("ok\n"); + int cpu, error; + printk("Thawing cpus ...\n"); + for_each_cpu_mask(cpu, frozen_cpus) { + error = smp_prepare_cpu(cpu); + if (!error) + error = cpu_up(cpu); + if (!error) { + printk("CPU%d is up\n", cpu); + continue; + } + printk("Error taking cpu %d up: %d\n", cpu, error); + panic("Not enough cpus"); + } + cpus_clear(frozen_cpus); } - diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 53f9f87..c285fc5 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -10,12 +10,12 @@ * This file is released under the GPLv2. * * I'd like to thank the following people for their work: - * + * * Pavel Machek <pavel@ucw.cz>: * Modifications, defectiveness pointing, being with me at the very beginning, * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. * - * Steve Doddi <dirk@loth.demon.co.uk>: + * Steve Doddi <dirk@loth.demon.co.uk>: * Support the possibility of hardware state restoring. * * Raph <grey.havens@earthling.net>: @@ -84,11 +84,11 @@ extern char resume_file[]; static unsigned int nr_copy_pages __nosavedata = 0; /* Suspend pagedir is allocated before final copy, therefore it - must be freed after resume + must be freed after resume Warning: this is evil. There are actually two pagedirs at time of resume. One is "pagedir_save", which is empty frame allocated at - time of suspend, that must be freed. Second is "pagedir_nosave", + time of suspend, that must be freed. Second is "pagedir_nosave", allocated at time of resume, that travels through memory not to collide with anything. @@ -132,7 +132,7 @@ static int mark_swapfiles(swp_entry_t prev) { int error; - rw_swap_page_sync(READ, + rw_swap_page_sync(READ, swp_entry(root_swap, 0), virt_to_page((unsigned long)&swsusp_header)); if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || @@ -140,7 +140,7 @@ static int mark_swapfiles(swp_entry_t prev) memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); memcpy(swsusp_header.sig,SWSUSP_SIG, 10); swsusp_header.swsusp_info = prev; - error = rw_swap_page_sync(WRITE, + error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0), virt_to_page((unsigned long) &swsusp_header)); @@ -174,22 +174,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info) static int swsusp_swap_check(void) /* This is called before saving image */ { int i, len; - + len=strlen(resume_file); root_swap = 0xFFFF; - + swap_list_lock(); - for(i=0; i<MAX_SWAPFILES; i++) { + for (i=0; i<MAX_SWAPFILES; i++) { if (swap_info[i].flags == 0) { swapfile_used[i]=SWAPFILE_UNUSED; } else { - if(!len) { + if (!len) { printk(KERN_WARNING "resume= option should be used to set suspend device" ); - if(root_swap == 0xFFFF) { + if (root_swap == 0xFFFF) { swapfile_used[i] = SWAPFILE_SUSPEND; root_swap = i; } else - swapfile_used[i] = SWAPFILE_IGNORED; + swapfile_used[i] = SWAPFILE_IGNORED; } else { /* we ignore all swap devices that are not the resume_file */ if (is_resume_device(&swap_info[i])) { @@ -209,15 +209,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */ * This is called after saving image so modification * will be lost after resume... and that's what we want. * we make the device unusable. A new call to - * lock_swapdevices can unlock the devices. + * lock_swapdevices can unlock the devices. */ static void lock_swapdevices(void) { int i; swap_list_lock(); - for(i = 0; i< MAX_SWAPFILES; i++) - if(swapfile_used[i] == SWAPFILE_IGNORED) { + for (i = 0; i< MAX_SWAPFILES; i++) + if (swapfile_used[i] == SWAPFILE_IGNORED) { swap_info[i].flags ^= 0xFF; } swap_list_unlock(); @@ -229,7 +229,7 @@ static void lock_swapdevices(void) * @loc: Place to store the entry we used. * * Allocate a new swap entry and 'sync' it. Note we discard -EIO - * errors. That is an artifact left over from swsusp. It did not + * errors. That is an artifact left over from swsusp. It did not * check the return of rw_swap_page_sync() at all, since most pages * written back to swap would return -EIO. * This is a partial improvement, since we will at least return other @@ -241,7 +241,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc) int error = 0; entry = get_swap_page(); - if (swp_offset(entry) && + if (swp_offset(entry) && swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { error = rw_swap_page_sync(WRITE, entry, virt_to_page(addr)); @@ -257,7 +257,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc) /** * data_free - Free the swap entries used by the saved image. * - * Walk the list of used swap entries and free each one. + * Walk the list of used swap entries and free each one. * This is only used for cleanup when suspend fails. */ static void data_free(void) @@ -290,7 +290,7 @@ static int data_write(void) mod = 1; printk( "Writing data to swap (%d pages)... ", nr_copy_pages ); - for_each_pbe(p, pagedir_nosave) { + for_each_pbe (p, pagedir_nosave) { if (!(i%mod)) printk( "\b\b\b\b%3d%%", i / mod ); if ((error = write_page(p->address, &(p->swap_address)))) @@ -335,7 +335,7 @@ static int close_swap(void) dump_info(); error = write_page((unsigned long)&swsusp_info, &entry); - if (!error) { + if (!error) { printk( "S" ); error = mark_swapfiles(entry); printk( "|\n" ); @@ -370,7 +370,7 @@ static int write_pagedir(void) struct pbe * pbe; printk( "Writing pagedir..."); - for_each_pb_page(pbe, pagedir_nosave) { + for_each_pb_page (pbe, pagedir_nosave) { if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++]))) return error; } @@ -472,7 +472,7 @@ static int save_highmem(void) int res = 0; pr_debug("swsusp: Saving Highmem\n"); - for_each_zone(zone) { + for_each_zone (zone) { if (is_highmem(zone)) res = save_highmem_zone(zone); if (res) @@ -547,7 +547,7 @@ static void count_data_pages(void) nr_copy_pages = 0; - for_each_zone(zone) { + for_each_zone (zone) { if (is_highmem(zone)) continue; mark_free_pages(zone); @@ -562,9 +562,9 @@ static void copy_data_pages(void) struct zone *zone; unsigned long zone_pfn; struct pbe * pbe = pagedir_nosave; - + pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); - for_each_zone(zone) { + for_each_zone (zone) { if (is_highmem(zone)) continue; mark_free_pages(zone); @@ -702,7 +702,7 @@ static void free_image_pages(void) { struct pbe * p; - for_each_pbe(p, pagedir_save) { + for_each_pbe (p, pagedir_save) { if (p->address) { ClearPageNosave(virt_to_page(p->address)); free_page(p->address); @@ -719,7 +719,7 @@ static int alloc_image_pages(void) { struct pbe * p; - for_each_pbe(p, pagedir_save) { + for_each_pbe (p, pagedir_save) { p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); if (!p->address) return -ENOMEM; @@ -740,7 +740,7 @@ void swsusp_free(void) /** * enough_free_mem - Make sure we enough free memory to snapshot. * - * Returns TRUE or FALSE after checking the number of available + * Returns TRUE or FALSE after checking the number of available * free pages. */ @@ -758,11 +758,11 @@ static int enough_free_mem(void) /** * enough_swap - Make sure we have enough swap to save the image. * - * Returns TRUE or FALSE after checking the total amount of swap + * Returns TRUE or FALSE after checking the total amount of swap * space avaiable. * * FIXME: si_swapinfo(&i) returns all swap devices information. - * We should only consider resume_device. + * We should only consider resume_device. */ static int enough_swap(void) @@ -781,18 +781,18 @@ static int swsusp_alloc(void) { int error; + pagedir_nosave = NULL; + nr_copy_pages = calc_nr(nr_copy_pages); + pr_debug("suspend: (pages needed: %d + %d free: %d)\n", nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); - pagedir_nosave = NULL; if (!enough_free_mem()) return -ENOMEM; if (!enough_swap()) return -ENOSPC; - nr_copy_pages = calc_nr(nr_copy_pages); - if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); return -ENOMEM; @@ -827,8 +827,8 @@ static int suspend_prepare_image(void) error = swsusp_alloc(); if (error) return error; - - /* During allocating of suspend pagedir, new cold pages may appear. + + /* During allocating of suspend pagedir, new cold pages may appear. * Kill them. */ drain_local_pages(); @@ -929,21 +929,6 @@ int swsusp_resume(void) return error; } -/* More restore stuff */ - -/* - * Returns true if given address/order collides with any orig_address - */ -static int does_collide_order(unsigned long addr, int order) -{ - int i; - - for (i=0; i < (1<<order); i++) - if (!PageNosaveFree(virt_to_page(addr + i * PAGE_SIZE))) - return 1; - return 0; -} - /** * On resume, for storing the PBE list and the image, * we can only use memory pages that do not conflict with the pages @@ -973,7 +958,7 @@ static unsigned long get_usable_page(unsigned gfp_mask) unsigned long m; m = get_zeroed_page(gfp_mask); - while (does_collide_order(m, 0)) { + while (!PageNosaveFree(virt_to_page(m))) { eat_page((void *)m); m = get_zeroed_page(gfp_mask); if (!m) @@ -1045,7 +1030,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) /* Set page flags */ - for_each_zone(zone) { + for_each_zone (zone) { for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) SetPageNosaveFree(pfn_to_page(zone_pfn + zone->zone_start_pfn)); @@ -1061,7 +1046,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) /* Relocate colliding pages */ for_each_pb_page (pbpage, pblist) { - if (does_collide_order((unsigned long)pbpage, 0)) { + if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) { m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); if (!m) { error = -ENOMEM; @@ -1193,8 +1178,10 @@ static const char * sanity_check(void) return "version"; if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) return "machine"; +#if 0 if(swsusp_info.cpus != num_online_cpus()) return "number of cpus"; +#endif return NULL; } diff --git a/kernel/printk.c b/kernel/printk.c index 3a442bf..5092397 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -588,8 +588,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) log_level_unknown = 1; } - if (!cpu_online(smp_processor_id()) && - system_state != SYSTEM_RUNNING) { + if (!cpu_online(smp_processor_id())) { /* * Some console drivers may assume that per-cpu resources have * been allocated. So don't allow them to be called by this diff --git a/kernel/resource.c b/kernel/resource.c index 52f696f..26967e0 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -263,7 +263,7 @@ static int find_resource(struct resource *root, struct resource *new, new->start = min; if (new->end > max) new->end = max; - new->start = (new->start + align - 1) & ~(align - 1); + new->start = ALIGN(new->start, align); if (alignf) alignf(alignf_data, new, size, align); if (new->start < new->end && new->end - new->start >= size - 1) { diff --git a/kernel/sched.c b/kernel/sched.c index 76080d1..a07cff9 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -166,7 +166,7 @@ #define SCALE_PRIO(x, prio) \ max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE) -static inline unsigned int task_timeslice(task_t *p) +static unsigned int task_timeslice(task_t *p) { if (p->static_prio < NICE_TO_PRIO(0)) return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio); @@ -206,7 +206,7 @@ struct runqueue { */ unsigned long nr_running; #ifdef CONFIG_SMP - unsigned long cpu_load; + unsigned long cpu_load[3]; #endif unsigned long long nr_switches; @@ -260,22 +260,86 @@ struct runqueue { static DEFINE_PER_CPU(struct runqueue, runqueues); +/* + * The domain tree (rq->sd) is protected by RCU's quiescent state transition. + * See detach_destroy_domains: synchronize_sched for details. + * + * The domain tree of any CPU may only be accessed from within + * preempt-disabled sections. + */ #define for_each_domain(cpu, domain) \ - for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent) +for (domain = rcu_dereference(cpu_rq(cpu)->sd); domain; domain = domain->parent) #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) #define this_rq() (&__get_cpu_var(runqueues)) #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) -/* - * Default context-switch locking: - */ #ifndef prepare_arch_switch -# define prepare_arch_switch(rq, next) do { } while (0) -# define finish_arch_switch(rq, next) spin_unlock_irq(&(rq)->lock) -# define task_running(rq, p) ((rq)->curr == (p)) +# define prepare_arch_switch(next) do { } while (0) +#endif +#ifndef finish_arch_switch +# define finish_arch_switch(prev) do { } while (0) +#endif + +#ifndef __ARCH_WANT_UNLOCKED_CTXSW +static inline int task_running(runqueue_t *rq, task_t *p) +{ + return rq->curr == p; +} + +static inline void prepare_lock_switch(runqueue_t *rq, task_t *next) +{ +} + +static inline void finish_lock_switch(runqueue_t *rq, task_t *prev) +{ + spin_unlock_irq(&rq->lock); +} + +#else /* __ARCH_WANT_UNLOCKED_CTXSW */ +static inline int task_running(runqueue_t *rq, task_t *p) +{ +#ifdef CONFIG_SMP + return p->oncpu; +#else + return rq->curr == p; +#endif +} + +static inline void prepare_lock_switch(runqueue_t *rq, task_t *next) +{ +#ifdef CONFIG_SMP + /* + * We can optimise this out completely for !SMP, because the + * SMP rebalancing from interrupt is the only thing that cares + * here. + */ + next->oncpu = 1; +#endif +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + spin_unlock_irq(&rq->lock); +#else + spin_unlock(&rq->lock); +#endif +} + +static inline void finish_lock_switch(runqueue_t *rq, task_t *prev) +{ +#ifdef CONFIG_SMP + /* + * After ->oncpu is cleared, the task can be moved to a different CPU. + * We must ensure this doesn't happen until the switch is completely + * finished. + */ + smp_wmb(); + prev->oncpu = 0; #endif +#ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW + local_irq_enable(); +#endif +} +#endif /* __ARCH_WANT_UNLOCKED_CTXSW */ /* * task_rq_lock - lock the runqueue a given task resides on and disable @@ -309,7 +373,7 @@ static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags) * bump this up when changing the output format or the meaning of an existing * format, so that tools can adapt (or abort) */ -#define SCHEDSTAT_VERSION 11 +#define SCHEDSTAT_VERSION 12 static int show_schedstat(struct seq_file *seq, void *v) { @@ -338,6 +402,7 @@ static int show_schedstat(struct seq_file *seq, void *v) #ifdef CONFIG_SMP /* domain-specific stats */ + preempt_disable(); for_each_domain(cpu, sd) { enum idle_type itype; char mask_str[NR_CPUS]; @@ -356,11 +421,13 @@ static int show_schedstat(struct seq_file *seq, void *v) sd->lb_nobusyq[itype], sd->lb_nobusyg[itype]); } - seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu\n", + seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", sd->alb_cnt, sd->alb_failed, sd->alb_pushed, - sd->sbe_pushed, sd->sbe_attempts, + sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed, + sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed, sd->ttwu_wake_remote, sd->ttwu_move_affine, sd->ttwu_move_balance); } + preempt_enable(); #endif } return 0; @@ -414,22 +481,6 @@ static inline runqueue_t *this_rq_lock(void) return rq; } -#ifdef CONFIG_SCHED_SMT -static int cpu_and_siblings_are_idle(int cpu) -{ - int sib; - for_each_cpu_mask(sib, cpu_sibling_map[cpu]) { - if (idle_cpu(sib)) - continue; - return 0; - } - - return 1; -} -#else -#define cpu_and_siblings_are_idle(A) idle_cpu(A) -#endif - #ifdef CONFIG_SCHEDSTATS /* * Called when a process is dequeued from the active array and given @@ -622,7 +673,7 @@ static inline void __activate_idle_task(task_t *p, runqueue_t *rq) rq->nr_running++; } -static void recalc_task_prio(task_t *p, unsigned long long now) +static int recalc_task_prio(task_t *p, unsigned long long now) { /* Caller must always ensure 'now >= p->timestamp' */ unsigned long long __sleep_time = now - p->timestamp; @@ -681,7 +732,7 @@ static void recalc_task_prio(task_t *p, unsigned long long now) } } - p->prio = effective_prio(p); + return effective_prio(p); } /* @@ -704,7 +755,7 @@ static void activate_task(task_t *p, runqueue_t *rq, int local) } #endif - recalc_task_prio(p, now); + p->prio = recalc_task_prio(p, now); /* * This checks to make sure it's not an uninterruptible task @@ -782,22 +833,12 @@ inline int task_curr(const task_t *p) } #ifdef CONFIG_SMP -enum request_type { - REQ_MOVE_TASK, - REQ_SET_DOMAIN, -}; - typedef struct { struct list_head list; - enum request_type type; - /* For REQ_MOVE_TASK */ task_t *task; int dest_cpu; - /* For REQ_SET_DOMAIN */ - struct sched_domain *sd; - struct completion done; } migration_req_t; @@ -819,7 +860,6 @@ static int migrate_task(task_t *p, int dest_cpu, migration_req_t *req) } init_completion(&req->done); - req->type = REQ_MOVE_TASK; req->task = p; req->dest_cpu = dest_cpu; list_add(&req->list, &rq->migration_queue); @@ -886,26 +926,154 @@ void kick_process(task_t *p) * We want to under-estimate the load of migration sources, to * balance conservatively. */ -static inline unsigned long source_load(int cpu) +static inline unsigned long source_load(int cpu, int type) { runqueue_t *rq = cpu_rq(cpu); unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE; + if (type == 0) + return load_now; - return min(rq->cpu_load, load_now); + return min(rq->cpu_load[type-1], load_now); } /* * Return a high guess at the load of a migration-target cpu */ -static inline unsigned long target_load(int cpu) +static inline unsigned long target_load(int cpu, int type) { runqueue_t *rq = cpu_rq(cpu); unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE; + if (type == 0) + return load_now; - return max(rq->cpu_load, load_now); + return max(rq->cpu_load[type-1], load_now); } -#endif +/* + * find_idlest_group finds and returns the least busy CPU group within the + * domain. + */ +static struct sched_group * +find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu) +{ + struct sched_group *idlest = NULL, *this = NULL, *group = sd->groups; + unsigned long min_load = ULONG_MAX, this_load = 0; + int load_idx = sd->forkexec_idx; + int imbalance = 100 + (sd->imbalance_pct-100)/2; + + do { + unsigned long load, avg_load; + int local_group; + int i; + + local_group = cpu_isset(this_cpu, group->cpumask); + /* XXX: put a cpus allowed check */ + + /* Tally up the load of all CPUs in the group */ + avg_load = 0; + + for_each_cpu_mask(i, group->cpumask) { + /* Bias balancing toward cpus of our domain */ + if (local_group) + load = source_load(i, load_idx); + else + load = target_load(i, load_idx); + + avg_load += load; + } + + /* Adjust by relative CPU power of the group */ + avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power; + + if (local_group) { + this_load = avg_load; + this = group; + } else if (avg_load < min_load) { + min_load = avg_load; + idlest = group; + } + group = group->next; + } while (group != sd->groups); + + if (!idlest || 100*this_load < imbalance*min_load) + return NULL; + return idlest; +} + +/* + * find_idlest_queue - find the idlest runqueue among the cpus in group. + */ +static int find_idlest_cpu(struct sched_group *group, int this_cpu) +{ + unsigned long load, min_load = ULONG_MAX; + int idlest = -1; + int i; + + for_each_cpu_mask(i, group->cpumask) { + load = source_load(i, 0); + + if (load < min_load || (load == min_load && i == this_cpu)) { + min_load = load; + idlest = i; + } + } + + return idlest; +} + +/* + * sched_balance_self: balance the current task (running on cpu) in domains + * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and + * SD_BALANCE_EXEC. + * + * Balance, ie. select the least loaded group. + * + * Returns the target CPU number, or the same CPU if no balancing is needed. + * + * preempt must be disabled. + */ +static int sched_balance_self(int cpu, int flag) +{ + struct task_struct *t = current; + struct sched_domain *tmp, *sd = NULL; + + for_each_domain(cpu, tmp) + if (tmp->flags & flag) + sd = tmp; + + while (sd) { + cpumask_t span; + struct sched_group *group; + int new_cpu; + int weight; + + span = sd->span; + group = find_idlest_group(sd, t, cpu); + if (!group) + goto nextlevel; + + new_cpu = find_idlest_cpu(group, cpu); + if (new_cpu == -1 || new_cpu == cpu) + goto nextlevel; + + /* Now try balancing at a lower domain level */ + cpu = new_cpu; +nextlevel: + sd = NULL; + weight = cpus_weight(span); + for_each_domain(cpu, tmp) { + if (weight <= cpus_weight(tmp->span)) + break; + if (tmp->flags & flag) + sd = tmp; + } + /* while loop will break here if sd == NULL */ + } + + return cpu; +} + +#endif /* CONFIG_SMP */ /* * wake_idle() will wake a task on an idle cpu if task->cpu is @@ -927,14 +1095,14 @@ static int wake_idle(int cpu, task_t *p) for_each_domain(cpu, sd) { if (sd->flags & SD_WAKE_IDLE) { - cpus_and(tmp, sd->span, cpu_online_map); - cpus_and(tmp, tmp, p->cpus_allowed); + cpus_and(tmp, sd->span, p->cpus_allowed); for_each_cpu_mask(i, tmp) { if (idle_cpu(i)) return i; } } - else break; + else + break; } return cpu; } @@ -967,7 +1135,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) runqueue_t *rq; #ifdef CONFIG_SMP unsigned long load, this_load; - struct sched_domain *sd; + struct sched_domain *sd, *this_sd = NULL; int new_cpu; #endif @@ -986,70 +1154,69 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) if (unlikely(task_running(rq, p))) goto out_activate; -#ifdef CONFIG_SCHEDSTATS + new_cpu = cpu; + schedstat_inc(rq, ttwu_cnt); if (cpu == this_cpu) { schedstat_inc(rq, ttwu_local); - } else { - for_each_domain(this_cpu, sd) { - if (cpu_isset(cpu, sd->span)) { - schedstat_inc(sd, ttwu_wake_remote); - break; - } + goto out_set_cpu; + } + + for_each_domain(this_cpu, sd) { + if (cpu_isset(cpu, sd->span)) { + schedstat_inc(sd, ttwu_wake_remote); + this_sd = sd; + break; } } -#endif - new_cpu = cpu; - if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed))) + if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed))) goto out_set_cpu; - load = source_load(cpu); - this_load = target_load(this_cpu); - /* - * If sync wakeup then subtract the (maximum possible) effect of - * the currently running task from the load of the current CPU: + * Check for affine wakeup and passive balancing possibilities. */ - if (sync) - this_load -= SCHED_LOAD_SCALE; + if (this_sd) { + int idx = this_sd->wake_idx; + unsigned int imbalance; - /* Don't pull the task off an idle CPU to a busy one */ - if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2) - goto out_set_cpu; + imbalance = 100 + (this_sd->imbalance_pct - 100) / 2; - new_cpu = this_cpu; /* Wake to this CPU if we can */ + load = source_load(cpu, idx); + this_load = target_load(this_cpu, idx); - /* - * Scan domains for affine wakeup and passive balancing - * possibilities. - */ - for_each_domain(this_cpu, sd) { - unsigned int imbalance; - /* - * Start passive balancing when half the imbalance_pct - * limit is reached. - */ - imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2; + new_cpu = this_cpu; /* Wake to this CPU if we can */ - if ((sd->flags & SD_WAKE_AFFINE) && - !task_hot(p, rq->timestamp_last_tick, sd)) { + if (this_sd->flags & SD_WAKE_AFFINE) { + unsigned long tl = this_load; /* - * This domain has SD_WAKE_AFFINE and p is cache cold - * in this domain. + * If sync wakeup then subtract the (maximum possible) + * effect of the currently running task from the load + * of the current CPU: */ - if (cpu_isset(cpu, sd->span)) { - schedstat_inc(sd, ttwu_move_affine); + if (sync) + tl -= SCHED_LOAD_SCALE; + + if ((tl <= load && + tl + target_load(cpu, idx) <= SCHED_LOAD_SCALE) || + 100*(tl + SCHED_LOAD_SCALE) <= imbalance*load) { + /* + * This domain has SD_WAKE_AFFINE and + * p is cache cold in this domain, and + * there is no bad imbalance. + */ + schedstat_inc(this_sd, ttwu_move_affine); goto out_set_cpu; } - } else if ((sd->flags & SD_WAKE_BALANCE) && - imbalance*this_load <= 100*load) { - /* - * This domain has SD_WAKE_BALANCE and there is - * an imbalance. - */ - if (cpu_isset(cpu, sd->span)) { - schedstat_inc(sd, ttwu_move_balance); + } + + /* + * Start passive balancing when half the imbalance_pct + * limit is reached. + */ + if (this_sd->flags & SD_WAKE_BALANCE) { + if (imbalance*this_load <= 100*load) { + schedstat_inc(this_sd, ttwu_move_balance); goto out_set_cpu; } } @@ -1120,17 +1287,19 @@ int fastcall wake_up_state(task_t *p, unsigned int state) return try_to_wake_up(p, state, 0); } -#ifdef CONFIG_SMP -static int find_idlest_cpu(struct task_struct *p, int this_cpu, - struct sched_domain *sd); -#endif - /* * Perform scheduler related setup for a newly forked process p. * p is forked by current. */ -void fastcall sched_fork(task_t *p) +void fastcall sched_fork(task_t *p, int clone_flags) { + int cpu = get_cpu(); + +#ifdef CONFIG_SMP + cpu = sched_balance_self(cpu, SD_BALANCE_FORK); +#endif + set_task_cpu(p, cpu); + /* * We mark the process as running here, but have not actually * inserted it onto the runqueue yet. This guarantees that @@ -1140,17 +1309,14 @@ void fastcall sched_fork(task_t *p) p->state = TASK_RUNNING; INIT_LIST_HEAD(&p->run_list); p->array = NULL; - spin_lock_init(&p->switch_lock); #ifdef CONFIG_SCHEDSTATS memset(&p->sched_info, 0, sizeof(p->sched_info)); #endif +#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) + p->oncpu = 0; +#endif #ifdef CONFIG_PREEMPT - /* - * During context-switch we hold precisely one spinlock, which - * schedule_tail drops. (in the common case it's this_rq()->lock, - * but it also can be p->switch_lock.) So we compensate with a count - * of 1. Also, we want to start with kernel preemption disabled. - */ + /* Want to start with kernel preemption disabled. */ p->thread_info->preempt_count = 1; #endif /* @@ -1174,12 +1340,10 @@ void fastcall sched_fork(task_t *p) * runqueue lock is not a problem. */ current->time_slice = 1; - preempt_disable(); scheduler_tick(); - local_irq_enable(); - preempt_enable(); - } else - local_irq_enable(); + } + local_irq_enable(); + put_cpu(); } /* @@ -1196,10 +1360,9 @@ void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags) runqueue_t *rq, *this_rq; rq = task_rq_lock(p, &flags); - cpu = task_cpu(p); - this_cpu = smp_processor_id(); - BUG_ON(p->state != TASK_RUNNING); + this_cpu = smp_processor_id(); + cpu = task_cpu(p); /* * We decrease the sleep average of forking parents @@ -1296,22 +1459,40 @@ void fastcall sched_exit(task_t * p) } /** + * prepare_task_switch - prepare to switch tasks + * @rq: the runqueue preparing to switch + * @next: the task we are going to switch to. + * + * This is called with the rq lock held and interrupts off. It must + * be paired with a subsequent finish_task_switch after the context + * switch. + * + * prepare_task_switch sets up locking and calls architecture specific + * hooks. + */ +static inline void prepare_task_switch(runqueue_t *rq, task_t *next) +{ + prepare_lock_switch(rq, next); + prepare_arch_switch(next); +} + +/** * finish_task_switch - clean up after a task-switch * @prev: the thread we just switched away from. * - * We enter this with the runqueue still locked, and finish_arch_switch() - * will unlock it along with doing any other architecture-specific cleanup - * actions. + * finish_task_switch must be called after the context switch, paired + * with a prepare_task_switch call before the context switch. + * finish_task_switch will reconcile locking set up by prepare_task_switch, + * and do any other architecture-specific cleanup actions. * * Note that we may have delayed dropping an mm in context_switch(). If * so, we finish that here outside of the runqueue lock. (Doing it * with the lock held can cause deadlocks; see schedule() for * details.) */ -static inline void finish_task_switch(task_t *prev) +static inline void finish_task_switch(runqueue_t *rq, task_t *prev) __releases(rq->lock) { - runqueue_t *rq = this_rq(); struct mm_struct *mm = rq->prev_mm; unsigned long prev_task_flags; @@ -1329,7 +1510,8 @@ static inline void finish_task_switch(task_t *prev) * Manfred Spraul <manfred@colorfullife.com> */ prev_task_flags = prev->flags; - finish_arch_switch(rq, prev); + finish_arch_switch(prev); + finish_lock_switch(rq, prev); if (mm) mmdrop(mm); if (unlikely(prev_task_flags & PF_DEAD)) @@ -1343,8 +1525,12 @@ static inline void finish_task_switch(task_t *prev) asmlinkage void schedule_tail(task_t *prev) __releases(rq->lock) { - finish_task_switch(prev); - + runqueue_t *rq = this_rq(); + finish_task_switch(rq, prev); +#ifdef __ARCH_WANT_UNLOCKED_CTXSW + /* In this case, finish_task_switch does not reenable preemption */ + preempt_enable(); +#endif if (current->set_child_tid) put_user(current->pid, current->set_child_tid); } @@ -1494,51 +1680,6 @@ static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest) } /* - * find_idlest_cpu - find the least busy runqueue. - */ -static int find_idlest_cpu(struct task_struct *p, int this_cpu, - struct sched_domain *sd) -{ - unsigned long load, min_load, this_load; - int i, min_cpu; - cpumask_t mask; - - min_cpu = UINT_MAX; - min_load = ULONG_MAX; - - cpus_and(mask, sd->span, p->cpus_allowed); - - for_each_cpu_mask(i, mask) { - load = target_load(i); - - if (load < min_load) { - min_cpu = i; - min_load = load; - - /* break out early on an idle CPU: */ - if (!min_load) - break; - } - } - - /* add +1 to account for the new task */ - this_load = source_load(this_cpu) + SCHED_LOAD_SCALE; - - /* - * Would with the addition of the new task to the - * current CPU there be an imbalance between this - * CPU and the idlest CPU? - * - * Use half of the balancing threshold - new-context is - * a good opportunity to balance. - */ - if (min_load*(100 + (sd->imbalance_pct-100)/2) < this_load*100) - return min_cpu; - - return this_cpu; -} - -/* * If dest_cpu is allowed for this process, migrate the task to it. * This is accomplished by forcing the cpu_allowed mask to only * allow dest_cpu, which will force the cpu onto dest_cpu. Then @@ -1571,37 +1712,16 @@ out: } /* - * sched_exec(): find the highest-level, exec-balance-capable - * domain and try to migrate the task to the least loaded CPU. - * - * execve() is a valuable balancing opportunity, because at this point - * the task has the smallest effective memory and cache footprint. + * sched_exec - execve() is a valuable balancing opportunity, because at + * this point the task has the smallest effective memory and cache footprint. */ void sched_exec(void) { - struct sched_domain *tmp, *sd = NULL; int new_cpu, this_cpu = get_cpu(); - - /* Prefer the current CPU if there's only this task running */ - if (this_rq()->nr_running <= 1) - goto out; - - for_each_domain(this_cpu, tmp) - if (tmp->flags & SD_BALANCE_EXEC) - sd = tmp; - - if (sd) { - schedstat_inc(sd, sbe_attempts); - new_cpu = find_idlest_cpu(current, this_cpu, sd); - if (new_cpu != this_cpu) { - schedstat_inc(sd, sbe_pushed); - put_cpu(); - sched_migrate_task(current, new_cpu); - return; - } - } -out: + new_cpu = sched_balance_self(this_cpu, SD_BALANCE_EXEC); put_cpu(); + if (new_cpu != this_cpu) + sched_migrate_task(current, new_cpu); } /* @@ -1632,7 +1752,7 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p, */ static inline int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu, - struct sched_domain *sd, enum idle_type idle) + struct sched_domain *sd, enum idle_type idle, int *all_pinned) { /* * We do not migrate tasks that are: @@ -1640,23 +1760,24 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu, * 2) cannot be migrated to this CPU due to cpus_allowed, or * 3) are cache-hot on their current CPU. */ - if (task_running(rq, p)) - return 0; if (!cpu_isset(this_cpu, p->cpus_allowed)) return 0; + *all_pinned = 0; + + if (task_running(rq, p)) + return 0; /* * Aggressive migration if: - * 1) the [whole] cpu is idle, or + * 1) task is cache cold, or * 2) too many balance attempts have failed. */ - if (cpu_and_siblings_are_idle(this_cpu) || \ - sd->nr_balance_failed > sd->cache_nice_tries) + if (sd->nr_balance_failed > sd->cache_nice_tries) return 1; if (task_hot(p, rq->timestamp_last_tick, sd)) - return 0; + return 0; return 1; } @@ -1669,16 +1790,18 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu, */ static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest, unsigned long max_nr_move, struct sched_domain *sd, - enum idle_type idle) + enum idle_type idle, int *all_pinned) { prio_array_t *array, *dst_array; struct list_head *head, *curr; - int idx, pulled = 0; + int idx, pulled = 0, pinned = 0; task_t *tmp; - if (max_nr_move <= 0 || busiest->nr_running <= 1) + if (max_nr_move == 0) goto out; + pinned = 1; + /* * We first consider expired tasks. Those will likely not be * executed in the near future, and they are most likely to @@ -1717,7 +1840,7 @@ skip_queue: curr = curr->prev; - if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle)) { + if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) { if (curr != head) goto skip_queue; idx++; @@ -1746,6 +1869,9 @@ out: * inside pull_task(). */ schedstat_add(sd, lb_gained[idle], pulled); + + if (all_pinned) + *all_pinned = pinned; return pulled; } @@ -1760,8 +1886,15 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, { struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups; unsigned long max_load, avg_load, total_load, this_load, total_pwr; + int load_idx; max_load = this_load = total_load = total_pwr = 0; + if (idle == NOT_IDLE) + load_idx = sd->busy_idx; + else if (idle == NEWLY_IDLE) + load_idx = sd->newidle_idx; + else + load_idx = sd->idle_idx; do { unsigned long load; @@ -1776,9 +1909,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, for_each_cpu_mask(i, group->cpumask) { /* Bias balancing toward cpus of our domain */ if (local_group) - load = target_load(i); + load = target_load(i, load_idx); else - load = source_load(i); + load = source_load(i, load_idx); avg_load += load; } @@ -1792,12 +1925,10 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, if (local_group) { this_load = avg_load; this = group; - goto nextgroup; } else if (avg_load > max_load) { max_load = avg_load; busiest = group; } -nextgroup: group = group->next; } while (group != sd->groups); @@ -1870,15 +2001,9 @@ nextgroup: /* Get rid of the scaling factor, rounding down as we divide */ *imbalance = *imbalance / SCHED_LOAD_SCALE; - return busiest; out_balanced: - if (busiest && (idle == NEWLY_IDLE || - (idle == SCHED_IDLE && max_load > SCHED_LOAD_SCALE)) ) { - *imbalance = 1; - return busiest; - } *imbalance = 0; return NULL; @@ -1894,7 +2019,7 @@ static runqueue_t *find_busiest_queue(struct sched_group *group) int i; for_each_cpu_mask(i, group->cpumask) { - load = source_load(i); + load = source_load(i, 0); if (load > max_load) { max_load = load; @@ -1906,6 +2031,12 @@ static runqueue_t *find_busiest_queue(struct sched_group *group) } /* + * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but + * so long as it is large enough. + */ +#define MAX_PINNED_INTERVAL 512 + +/* * Check this_cpu to ensure it is balanced within domain. Attempt to move * tasks if there is an imbalance. * @@ -1917,7 +2048,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, struct sched_group *group; runqueue_t *busiest; unsigned long imbalance; - int nr_moved; + int nr_moved, all_pinned = 0; + int active_balance = 0; spin_lock(&this_rq->lock); schedstat_inc(sd, lb_cnt[idle]); @@ -1934,15 +2066,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, goto out_balanced; } - /* - * This should be "impossible", but since load - * balancing is inherently racy and statistical, - * it could happen in theory. - */ - if (unlikely(busiest == this_rq)) { - WARN_ON(1); - goto out_balanced; - } + BUG_ON(busiest == this_rq); schedstat_add(sd, lb_imbalance[idle], imbalance); @@ -1956,9 +2080,15 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, */ double_lock_balance(this_rq, busiest); nr_moved = move_tasks(this_rq, this_cpu, busiest, - imbalance, sd, idle); + imbalance, sd, idle, + &all_pinned); spin_unlock(&busiest->lock); + + /* All tasks on this runqueue were pinned by CPU affinity */ + if (unlikely(all_pinned)) + goto out_balanced; } + spin_unlock(&this_rq->lock); if (!nr_moved) { @@ -1966,36 +2096,38 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, sd->nr_balance_failed++; if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) { - int wake = 0; spin_lock(&busiest->lock); if (!busiest->active_balance) { busiest->active_balance = 1; busiest->push_cpu = this_cpu; - wake = 1; + active_balance = 1; } spin_unlock(&busiest->lock); - if (wake) + if (active_balance) wake_up_process(busiest->migration_thread); /* * We've kicked active balancing, reset the failure * counter. */ - sd->nr_balance_failed = sd->cache_nice_tries; + sd->nr_balance_failed = sd->cache_nice_tries+1; } - - /* - * We were unbalanced, but unsuccessful in move_tasks(), - * so bump the balance_interval to lessen the lock contention. - */ - if (sd->balance_interval < sd->max_interval) - sd->balance_interval++; - } else { + } else sd->nr_balance_failed = 0; + if (likely(!active_balance)) { /* We were unbalanced, so reset the balancing interval */ sd->balance_interval = sd->min_interval; + } else { + /* + * If we've begun active balancing, start to back off. This + * case may not be covered by the all_pinned logic if there + * is only 1 task on the busy runqueue (because we don't call + * move_tasks). + */ + if (sd->balance_interval < sd->max_interval) + sd->balance_interval *= 2; } return nr_moved; @@ -2005,8 +2137,10 @@ out_balanced: schedstat_inc(sd, lb_balanced[idle]); + sd->nr_balance_failed = 0; /* tune up the balancing interval */ - if (sd->balance_interval < sd->max_interval) + if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) || + (sd->balance_interval < sd->max_interval)) sd->balance_interval *= 2; return 0; @@ -2030,31 +2164,36 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq, schedstat_inc(sd, lb_cnt[NEWLY_IDLE]); group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE); if (!group) { - schedstat_inc(sd, lb_balanced[NEWLY_IDLE]); schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]); - goto out; + goto out_balanced; } busiest = find_busiest_queue(group); - if (!busiest || busiest == this_rq) { - schedstat_inc(sd, lb_balanced[NEWLY_IDLE]); + if (!busiest) { schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]); - goto out; + goto out_balanced; } + BUG_ON(busiest == this_rq); + /* Attempt to move tasks */ double_lock_balance(this_rq, busiest); schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance); nr_moved = move_tasks(this_rq, this_cpu, busiest, - imbalance, sd, NEWLY_IDLE); + imbalance, sd, NEWLY_IDLE, NULL); if (!nr_moved) schedstat_inc(sd, lb_failed[NEWLY_IDLE]); + else + sd->nr_balance_failed = 0; spin_unlock(&busiest->lock); - -out: return nr_moved; + +out_balanced: + schedstat_inc(sd, lb_balanced[NEWLY_IDLE]); + sd->nr_balance_failed = 0; + return 0; } /* @@ -2086,56 +2225,42 @@ static inline void idle_balance(int this_cpu, runqueue_t *this_rq) static void active_load_balance(runqueue_t *busiest_rq, int busiest_cpu) { struct sched_domain *sd; - struct sched_group *cpu_group; runqueue_t *target_rq; - cpumask_t visited_cpus; - int cpu; + int target_cpu = busiest_rq->push_cpu; + + if (busiest_rq->nr_running <= 1) + /* no task to move */ + return; + + target_rq = cpu_rq(target_cpu); /* - * Search for suitable CPUs to push tasks to in successively higher - * domains with SD_LOAD_BALANCE set. + * This condition is "impossible", if it occurs + * we need to fix it. Originally reported by + * Bjorn Helgaas on a 128-cpu setup. */ - visited_cpus = CPU_MASK_NONE; - for_each_domain(busiest_cpu, sd) { - if (!(sd->flags & SD_LOAD_BALANCE)) - /* no more domains to search */ - break; + BUG_ON(busiest_rq == target_rq); - schedstat_inc(sd, alb_cnt); + /* move a task from busiest_rq to target_rq */ + double_lock_balance(busiest_rq, target_rq); - cpu_group = sd->groups; - do { - for_each_cpu_mask(cpu, cpu_group->cpumask) { - if (busiest_rq->nr_running <= 1) - /* no more tasks left to move */ - return; - if (cpu_isset(cpu, visited_cpus)) - continue; - cpu_set(cpu, visited_cpus); - if (!cpu_and_siblings_are_idle(cpu) || cpu == busiest_cpu) - continue; - - target_rq = cpu_rq(cpu); - /* - * This condition is "impossible", if it occurs - * we need to fix it. Originally reported by - * Bjorn Helgaas on a 128-cpu setup. - */ - BUG_ON(busiest_rq == target_rq); - - /* move a task from busiest_rq to target_rq */ - double_lock_balance(busiest_rq, target_rq); - if (move_tasks(target_rq, cpu, busiest_rq, - 1, sd, SCHED_IDLE)) { - schedstat_inc(sd, alb_pushed); - } else { - schedstat_inc(sd, alb_failed); - } - spin_unlock(&target_rq->lock); - } - cpu_group = cpu_group->next; - } while (cpu_group != sd->groups); - } + /* Search for an sd spanning us and the target CPU. */ + for_each_domain(target_cpu, sd) + if ((sd->flags & SD_LOAD_BALANCE) && + cpu_isset(busiest_cpu, sd->span)) + break; + + if (unlikely(sd == NULL)) + goto out; + + schedstat_inc(sd, alb_cnt); + + if (move_tasks(target_rq, target_cpu, busiest_rq, 1, sd, SCHED_IDLE, NULL)) + schedstat_inc(sd, alb_pushed); + else + schedstat_inc(sd, alb_failed); +out: + spin_unlock(&target_rq->lock); } /* @@ -2156,18 +2281,23 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq, unsigned long old_load, this_load; unsigned long j = jiffies + CPU_OFFSET(this_cpu); struct sched_domain *sd; + int i; - /* Update our load */ - old_load = this_rq->cpu_load; this_load = this_rq->nr_running * SCHED_LOAD_SCALE; - /* - * Round up the averaging division if load is increasing. This - * prevents us from getting stuck on 9 if the load is 10, for - * example. - */ - if (this_load > old_load) - old_load++; - this_rq->cpu_load = (old_load + this_load) / 2; + /* Update our load */ + for (i = 0; i < 3; i++) { + unsigned long new_load = this_load; + int scale = 1 << i; + old_load = this_rq->cpu_load[i]; + /* + * Round up the averaging division if load is increasing. This + * prevents us from getting stuck on 9 if the load is 10, for + * example. + */ + if (new_load > old_load) + new_load += scale-1; + this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) / scale; + } for_each_domain(this_cpu, sd) { unsigned long interval; @@ -2447,11 +2577,15 @@ out: #ifdef CONFIG_SCHED_SMT static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq) { - struct sched_domain *sd = this_rq->sd; + struct sched_domain *tmp, *sd = NULL; cpumask_t sibling_map; int i; - if (!(sd->flags & SD_SHARE_CPUPOWER)) + for_each_domain(this_cpu, tmp) + if (tmp->flags & SD_SHARE_CPUPOWER) + sd = tmp; + + if (!sd) return; /* @@ -2492,13 +2626,17 @@ static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq) static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq) { - struct sched_domain *sd = this_rq->sd; + struct sched_domain *tmp, *sd = NULL; cpumask_t sibling_map; prio_array_t *array; int ret = 0, i; task_t *p; - if (!(sd->flags & SD_SHARE_CPUPOWER)) + for_each_domain(this_cpu, tmp) + if (tmp->flags & SD_SHARE_CPUPOWER) + sd = tmp; + + if (!sd) return 0; /* @@ -2613,7 +2751,7 @@ asmlinkage void __sched schedule(void) struct list_head *queue; unsigned long long now; unsigned long run_time; - int cpu, idx; + int cpu, idx, new_prio; /* * Test if we are atomic. Since do_exit() needs to call into @@ -2735,9 +2873,14 @@ go_idle: delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128; array = next->array; - dequeue_task(next, array); - recalc_task_prio(next, next->timestamp + delta); - enqueue_task(next, array); + new_prio = recalc_task_prio(next, next->timestamp + delta); + + if (unlikely(next->prio != new_prio)) { + dequeue_task(next, array); + next->prio = new_prio; + enqueue_task(next, array); + } else + requeue_task(next, array); } next->activated = 0; switch_tasks: @@ -2761,11 +2904,15 @@ switch_tasks: rq->curr = next; ++*switch_count; - prepare_arch_switch(rq, next); + prepare_task_switch(rq, next); prev = context_switch(rq, prev, next); barrier(); - - finish_task_switch(prev); + /* + * this_rq must be evaluated again because prev may have moved + * CPUs since it called schedule(), thus the 'rq' on its stack + * frame will be invalid. + */ + finish_task_switch(this_rq(), prev); } else spin_unlock_irq(&rq->lock); @@ -3384,13 +3531,24 @@ recheck: if ((policy == SCHED_NORMAL) != (param->sched_priority == 0)) return -EINVAL; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && - param->sched_priority > p->signal->rlim[RLIMIT_RTPRIO].rlim_cur && - !capable(CAP_SYS_NICE)) - return -EPERM; - if ((current->euid != p->euid) && (current->euid != p->uid) && - !capable(CAP_SYS_NICE)) - return -EPERM; + /* + * Allow unprivileged RT tasks to decrease priority: + */ + if (!capable(CAP_SYS_NICE)) { + /* can't change policy */ + if (policy != p->policy) + return -EPERM; + /* can't increase priority */ + if (policy != SCHED_NORMAL && + param->sched_priority > p->rt_priority && + param->sched_priority > + p->signal->rlim[RLIMIT_RTPRIO].rlim_cur) + return -EPERM; + /* can't change other user's priorities */ + if ((current->euid != p->euid) && + (current->euid != p->uid)) + return -EPERM; + } retval = security_task_setscheduler(p, policy, param); if (retval) @@ -4030,6 +4188,9 @@ void __devinit init_idle(task_t *idle, int cpu) spin_lock_irqsave(&rq->lock, flags); rq->curr = rq->idle = idle; +#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) + idle->oncpu = 1; +#endif set_tsk_need_resched(idle); spin_unlock_irqrestore(&rq->lock, flags); @@ -4174,8 +4335,7 @@ static int migration_thread(void * data) struct list_head *head; migration_req_t *req; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); spin_lock_irq(&rq->lock); @@ -4200,17 +4360,9 @@ static int migration_thread(void * data) req = list_entry(head->next, migration_req_t, list); list_del_init(head->next); - if (req->type == REQ_MOVE_TASK) { - spin_unlock(&rq->lock); - __migrate_task(req->task, cpu, req->dest_cpu); - local_irq_enable(); - } else if (req->type == REQ_SET_DOMAIN) { - rq->sd = req->sd; - spin_unlock_irq(&rq->lock); - } else { - spin_unlock_irq(&rq->lock); - WARN_ON(1); - } + spin_unlock(&rq->lock); + __migrate_task(req->task, cpu, req->dest_cpu); + local_irq_enable(); complete(&req->done); } @@ -4441,7 +4593,6 @@ static int migration_call(struct notifier_block *nfb, unsigned long action, migration_req_t *req; req = list_entry(rq->migration_queue.next, migration_req_t, list); - BUG_ON(req->type != REQ_MOVE_TASK); list_del_init(&req->list); complete(&req->done); } @@ -4472,12 +4623,17 @@ int __init migration_init(void) #endif #ifdef CONFIG_SMP -#define SCHED_DOMAIN_DEBUG +#undef SCHED_DOMAIN_DEBUG #ifdef SCHED_DOMAIN_DEBUG static void sched_domain_debug(struct sched_domain *sd, int cpu) { int level = 0; + if (!sd) { + printk(KERN_DEBUG "CPU%d attaching NULL sched-domain.\n", cpu); + return; + } + printk(KERN_DEBUG "CPU%d attaching sched-domain:\n", cpu); do { @@ -4560,37 +4716,81 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu) #define sched_domain_debug(sd, cpu) {} #endif +static int sd_degenerate(struct sched_domain *sd) +{ + if (cpus_weight(sd->span) == 1) + return 1; + + /* Following flags need at least 2 groups */ + if (sd->flags & (SD_LOAD_BALANCE | + SD_BALANCE_NEWIDLE | + SD_BALANCE_FORK | + SD_BALANCE_EXEC)) { + if (sd->groups != sd->groups->next) + return 0; + } + + /* Following flags don't use groups */ + if (sd->flags & (SD_WAKE_IDLE | + SD_WAKE_AFFINE | + SD_WAKE_BALANCE)) + return 0; + + return 1; +} + +static int sd_parent_degenerate(struct sched_domain *sd, + struct sched_domain *parent) +{ + unsigned long cflags = sd->flags, pflags = parent->flags; + + if (sd_degenerate(parent)) + return 1; + + if (!cpus_equal(sd->span, parent->span)) + return 0; + + /* Does parent contain flags not in child? */ + /* WAKE_BALANCE is a subset of WAKE_AFFINE */ + if (cflags & SD_WAKE_AFFINE) + pflags &= ~SD_WAKE_BALANCE; + /* Flags needing groups don't count if only 1 group in parent */ + if (parent->groups == parent->groups->next) { + pflags &= ~(SD_LOAD_BALANCE | + SD_BALANCE_NEWIDLE | + SD_BALANCE_FORK | + SD_BALANCE_EXEC); + } + if (~cflags & pflags) + return 0; + + return 1; +} + /* * Attach the domain 'sd' to 'cpu' as its base domain. Callers must * hold the hotplug lock. */ -void __devinit cpu_attach_domain(struct sched_domain *sd, int cpu) +void cpu_attach_domain(struct sched_domain *sd, int cpu) { - migration_req_t req; - unsigned long flags; runqueue_t *rq = cpu_rq(cpu); - int local = 1; - - sched_domain_debug(sd, cpu); + struct sched_domain *tmp; - spin_lock_irqsave(&rq->lock, flags); - - if (cpu == smp_processor_id() || !cpu_online(cpu)) { - rq->sd = sd; - } else { - init_completion(&req.done); - req.type = REQ_SET_DOMAIN; - req.sd = sd; - list_add(&req.list, &rq->migration_queue); - local = 0; + /* Remove the sched domains which do not contribute to scheduling. */ + for (tmp = sd; tmp; tmp = tmp->parent) { + struct sched_domain *parent = tmp->parent; + if (!parent) + break; + if (sd_parent_degenerate(tmp, parent)) + tmp->parent = parent->parent; } - spin_unlock_irqrestore(&rq->lock, flags); + if (sd && sd_degenerate(sd)) + sd = sd->parent; - if (!local) { - wake_up_process(rq->migration_thread); - wait_for_completion(&req.done); - } + sched_domain_debug(sd, cpu); + + rcu_assign_pointer(rq->sd, sd); } /* cpus with isolated domains */ @@ -4622,7 +4822,7 @@ __setup ("isolcpus=", isolated_cpu_setup); * covered by the given span, and will set each group's ->cpumask correctly, * and ->cpu_power to 0. */ -void __devinit init_sched_build_groups(struct sched_group groups[], +void init_sched_build_groups(struct sched_group groups[], cpumask_t span, int (*group_fn)(int cpu)) { struct sched_group *first = NULL, *last = NULL; @@ -4658,13 +4858,14 @@ void __devinit init_sched_build_groups(struct sched_group groups[], #ifdef ARCH_HAS_SCHED_DOMAIN -extern void __devinit arch_init_sched_domains(void); -extern void __devinit arch_destroy_sched_domains(void); +extern void build_sched_domains(const cpumask_t *cpu_map); +extern void arch_init_sched_domains(const cpumask_t *cpu_map); +extern void arch_destroy_sched_domains(const cpumask_t *cpu_map); #else #ifdef CONFIG_SCHED_SMT static DEFINE_PER_CPU(struct sched_domain, cpu_domains); static struct sched_group sched_group_cpus[NR_CPUS]; -static int __devinit cpu_to_cpu_group(int cpu) +static int cpu_to_cpu_group(int cpu) { return cpu; } @@ -4672,7 +4873,7 @@ static int __devinit cpu_to_cpu_group(int cpu) static DEFINE_PER_CPU(struct sched_domain, phys_domains); static struct sched_group sched_group_phys[NR_CPUS]; -static int __devinit cpu_to_phys_group(int cpu) +static int cpu_to_phys_group(int cpu) { #ifdef CONFIG_SCHED_SMT return first_cpu(cpu_sibling_map[cpu]); @@ -4685,7 +4886,7 @@ static int __devinit cpu_to_phys_group(int cpu) static DEFINE_PER_CPU(struct sched_domain, node_domains); static struct sched_group sched_group_nodes[MAX_NUMNODES]; -static int __devinit cpu_to_node_group(int cpu) +static int cpu_to_node_group(int cpu) { return cpu_to_node(cpu); } @@ -4716,39 +4917,28 @@ static void check_sibling_maps(void) #endif /* - * Set up scheduler domains and groups. Callers must hold the hotplug lock. + * Build sched domains for a given set of cpus and attach the sched domains + * to the individual cpus */ -static void __devinit arch_init_sched_domains(void) +static void build_sched_domains(const cpumask_t *cpu_map) { int i; - cpumask_t cpu_default_map; - -#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA) - check_sibling_maps(); -#endif - /* - * Setup mask for cpus without special case scheduling requirements. - * For now this just excludes isolated cpus, but could be used to - * exclude other special cases in the future. - */ - cpus_complement(cpu_default_map, cpu_isolated_map); - cpus_and(cpu_default_map, cpu_default_map, cpu_online_map); /* - * Set up domains. Isolated domains just stay on the dummy domain. + * Set up domains for cpus specified by the cpu_map. */ - for_each_cpu_mask(i, cpu_default_map) { + for_each_cpu_mask(i, *cpu_map) { int group; struct sched_domain *sd = NULL, *p; cpumask_t nodemask = node_to_cpumask(cpu_to_node(i)); - cpus_and(nodemask, nodemask, cpu_default_map); + cpus_and(nodemask, nodemask, *cpu_map); #ifdef CONFIG_NUMA sd = &per_cpu(node_domains, i); group = cpu_to_node_group(i); *sd = SD_NODE_INIT; - sd->span = cpu_default_map; + sd->span = *cpu_map; sd->groups = &sched_group_nodes[group]; #endif @@ -4766,7 +4956,7 @@ static void __devinit arch_init_sched_domains(void) group = cpu_to_cpu_group(i); *sd = SD_SIBLING_INIT; sd->span = cpu_sibling_map[i]; - cpus_and(sd->span, sd->span, cpu_default_map); + cpus_and(sd->span, sd->span, *cpu_map); sd->parent = p; sd->groups = &sched_group_cpus[group]; #endif @@ -4776,7 +4966,7 @@ static void __devinit arch_init_sched_domains(void) /* Set up CPU (sibling) groups */ for_each_online_cpu(i) { cpumask_t this_sibling_map = cpu_sibling_map[i]; - cpus_and(this_sibling_map, this_sibling_map, cpu_default_map); + cpus_and(this_sibling_map, this_sibling_map, *cpu_map); if (i != first_cpu(this_sibling_map)) continue; @@ -4789,7 +4979,7 @@ static void __devinit arch_init_sched_domains(void) for (i = 0; i < MAX_NUMNODES; i++) { cpumask_t nodemask = node_to_cpumask(i); - cpus_and(nodemask, nodemask, cpu_default_map); + cpus_and(nodemask, nodemask, *cpu_map); if (cpus_empty(nodemask)) continue; @@ -4799,12 +4989,12 @@ static void __devinit arch_init_sched_domains(void) #ifdef CONFIG_NUMA /* Set up node groups */ - init_sched_build_groups(sched_group_nodes, cpu_default_map, + init_sched_build_groups(sched_group_nodes, *cpu_map, &cpu_to_node_group); #endif /* Calculate CPU power for physical packages and nodes */ - for_each_cpu_mask(i, cpu_default_map) { + for_each_cpu_mask(i, *cpu_map) { int power; struct sched_domain *sd; #ifdef CONFIG_SCHED_SMT @@ -4828,7 +5018,7 @@ static void __devinit arch_init_sched_domains(void) } /* Attach the domains */ - for_each_online_cpu(i) { + for_each_cpu_mask(i, *cpu_map) { struct sched_domain *sd; #ifdef CONFIG_SCHED_SMT sd = &per_cpu(cpu_domains, i); @@ -4838,41 +5028,85 @@ static void __devinit arch_init_sched_domains(void) cpu_attach_domain(sd, i); } } +/* + * Set up scheduler domains and groups. Callers must hold the hotplug lock. + */ +static void arch_init_sched_domains(cpumask_t *cpu_map) +{ + cpumask_t cpu_default_map; + +#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA) + check_sibling_maps(); +#endif + /* + * Setup mask for cpus without special case scheduling requirements. + * For now this just excludes isolated cpus, but could be used to + * exclude other special cases in the future. + */ + cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map); + + build_sched_domains(&cpu_default_map); +} -#ifdef CONFIG_HOTPLUG_CPU -static void __devinit arch_destroy_sched_domains(void) +static void arch_destroy_sched_domains(const cpumask_t *cpu_map) { /* Do nothing: everything is statically allocated. */ } -#endif #endif /* ARCH_HAS_SCHED_DOMAIN */ /* - * Initial dummy domain for early boot and for hotplug cpu. Being static, - * it is initialized to zero, so all balancing flags are cleared which is - * what we want. + * Detach sched domains from a group of cpus specified in cpu_map + * These cpus will now be attached to the NULL domain */ -static struct sched_domain sched_domain_dummy; +static inline void detach_destroy_domains(const cpumask_t *cpu_map) +{ + int i; + + for_each_cpu_mask(i, *cpu_map) + cpu_attach_domain(NULL, i); + synchronize_sched(); + arch_destroy_sched_domains(cpu_map); +} + +/* + * Partition sched domains as specified by the cpumasks below. + * This attaches all cpus from the cpumasks to the NULL domain, + * waits for a RCU quiescent period, recalculates sched + * domain information and then attaches them back to the + * correct sched domains + * Call with hotplug lock held + */ +void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2) +{ + cpumask_t change_map; + + cpus_and(*partition1, *partition1, cpu_online_map); + cpus_and(*partition2, *partition2, cpu_online_map); + cpus_or(change_map, *partition1, *partition2); + + /* Detach sched domains from all of the affected cpus */ + detach_destroy_domains(&change_map); + if (!cpus_empty(*partition1)) + build_sched_domains(partition1); + if (!cpus_empty(*partition2)) + build_sched_domains(partition2); +} #ifdef CONFIG_HOTPLUG_CPU /* * Force a reinitialization of the sched domains hierarchy. The domains * and groups cannot be updated in place without racing with the balancing - * code, so we temporarily attach all running cpus to a "dummy" domain + * code, so we temporarily attach all running cpus to the NULL domain * which will prevent rebalancing while the sched domains are recalculated. */ static int update_sched_domains(struct notifier_block *nfb, unsigned long action, void *hcpu) { - int i; - switch (action) { case CPU_UP_PREPARE: case CPU_DOWN_PREPARE: - for_each_online_cpu(i) - cpu_attach_domain(&sched_domain_dummy, i); - arch_destroy_sched_domains(); + detach_destroy_domains(&cpu_online_map); return NOTIFY_OK; case CPU_UP_CANCELED: @@ -4888,7 +5122,7 @@ static int update_sched_domains(struct notifier_block *nfb, } /* The hotplug lock is already held by cpu_up/cpu_down */ - arch_init_sched_domains(); + arch_init_sched_domains(&cpu_online_map); return NOTIFY_OK; } @@ -4897,7 +5131,7 @@ static int update_sched_domains(struct notifier_block *nfb, void __init sched_init_smp(void) { lock_cpu_hotplug(); - arch_init_sched_domains(); + arch_init_sched_domains(&cpu_online_map); unlock_cpu_hotplug(); /* XXX: Theoretical race here - CPU may be hotplugged now */ hotcpu_notifier(update_sched_domains, 0); @@ -4927,13 +5161,15 @@ void __init sched_init(void) rq = cpu_rq(i); spin_lock_init(&rq->lock); + rq->nr_running = 0; rq->active = rq->arrays; rq->expired = rq->arrays + 1; rq->best_expired_prio = MAX_PRIO; #ifdef CONFIG_SMP - rq->sd = &sched_domain_dummy; - rq->cpu_load = 0; + rq->sd = NULL; + for (j = 1; j < 3; j++) + rq->cpu_load[j] = 0; rq->active_balance = 0; rq->push_cpu = 0; rq->migration_thread = NULL; diff --git a/kernel/signal.c b/kernel/signal.c index d125872..ca1186e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -213,7 +213,7 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) fastcall void recalc_sigpending_tsk(struct task_struct *t) { if (t->signal->group_stop_count > 0 || - (t->flags & PF_FREEZE) || + (freezing(t)) || PENDING(&t->pending, &t->blocked) || PENDING(&t->signal->shared_pending, &t->blocked)) set_tsk_thread_flag(t, TIF_SIGPENDING); @@ -2231,8 +2231,7 @@ sys_rt_sigtimedwait(const sigset_t __user *uthese, current->state = TASK_INTERRUPTIBLE; timeout = schedule_timeout(timeout); - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &these, &info); current->blocked = current->real_blocked; diff --git a/kernel/sys.c b/kernel/sys.c index da24bc1..9a24374 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -16,6 +16,8 @@ #include <linux/init.h> #include <linux/highuid.h> #include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/kexec.h> #include <linux/workqueue.h> #include <linux/device.h> #include <linux/key.h> @@ -405,6 +407,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user case LINUX_REBOOT_CMD_HALT: notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); system_state = SYSTEM_HALT; + device_suspend(PMSG_SUSPEND); device_shutdown(); printk(KERN_EMERG "System halted.\n"); machine_halt(); @@ -415,6 +418,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user case LINUX_REBOOT_CMD_POWER_OFF: notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); system_state = SYSTEM_POWER_OFF; + device_suspend(PMSG_SUSPEND); device_shutdown(); printk(KERN_EMERG "Power down.\n"); machine_power_off(); @@ -431,11 +435,30 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer); system_state = SYSTEM_RESTART; + device_suspend(PMSG_FREEZE); device_shutdown(); printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer); machine_restart(buffer); break; +#ifdef CONFIG_KEXEC + case LINUX_REBOOT_CMD_KEXEC: + { + struct kimage *image; + image = xchg(&kexec_image, 0); + if (!image) { + unlock_kernel(); + return -EINVAL; + } + notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); + system_state = SYSTEM_RESTART; + device_shutdown(); + printk(KERN_EMERG "Starting new kernel\n"); + machine_shutdown(); + machine_kexec(image); + break; + } +#endif #ifdef CONFIG_SOFTWARE_SUSPEND case LINUX_REBOOT_CMD_SW_SUSPEND: { diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 6f15bea..29196ce 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -18,6 +18,8 @@ cond_syscall(sys_acct); cond_syscall(sys_lookup_dcookie); cond_syscall(sys_swapon); cond_syscall(sys_swapoff); +cond_syscall(sys_kexec_load); +cond_syscall(compat_sys_kexec_load); cond_syscall(sys_init_module); cond_syscall(sys_delete_module); cond_syscall(sys_socketpair); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 24a4d12..270ee7f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1000,8 +1000,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol int error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table, &context); - if (context) - kfree(context); + kfree(context); if (error != -ENOTDIR) return error; tmp = tmp->next; diff --git a/kernel/timer.c b/kernel/timer.c index 51ff917..f2a1188 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1597,7 +1597,7 @@ void msleep(unsigned int msecs) EXPORT_SYMBOL(msleep); /** - * msleep_interruptible - sleep waiting for waitqueue interruptions + * msleep_interruptible - sleep waiting for signals * @msecs: Time in milliseconds to sleep for */ unsigned long msleep_interruptible(unsigned int msecs) diff --git a/lib/Kconfig b/lib/Kconfig index 455833a..eeb429a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -63,32 +63,16 @@ config REED_SOLOMON_ENC16 config REED_SOLOMON_DEC16 boolean +# +# Textsearch support is select'ed if needed +# config TEXTSEARCH - boolean "Textsearch infrastructure" - default y - help - Say Y here if you want to provide a textsearch infrastructure - to other subsystems. + boolean config TEXTSEARCH_KMP - depends on TEXTSEARCH - tristate "Knuth-Morris-Pratt" - help - Say Y here if you want to be able to search text using the - Knuth-Morris-Pratt textsearch algorithm. - - To compile this code as a module, choose M here: the - module will be called ts_kmp. + tristate config TEXTSEARCH_FSM - depends on TEXTSEARCH - tristate "Finite state machine" - help - Say Y here if you want to be able to search text using a - naive finite state machine approach implementing a subset - of regular expressions. - - To compile this code as a module, choose M here: the - module will be called ts_fsm. + tristate endmenu diff --git a/lib/bitmap.c b/lib/bitmap.c index d1388a5..fb9371f 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -289,7 +289,6 @@ EXPORT_SYMBOL(__bitmap_weight); #define CHUNKSZ 32 #define nbits_to_hold_value(val) fls(val) -#define roundup_power2(val,modulus) (((val) + (modulus) - 1) & ~((modulus) - 1)) #define unhex(c) (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10)) #define BASEDEC 10 /* fancier cpuset lists input in decimal */ @@ -316,7 +315,7 @@ int bitmap_scnprintf(char *buf, unsigned int buflen, if (chunksz == 0) chunksz = CHUNKSZ; - i = roundup_power2(nmaskbits, CHUNKSZ) - CHUNKSZ; + i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ; for (; i >= 0; i -= CHUNKSZ) { chunkmask = ((1ULL << chunksz) - 1); word = i / BITS_PER_LONG; @@ -41,7 +41,7 @@ void sha_transform(__u32 *digest, const char *in, __u32 *W) __u32 a, b, c, d, e, t, i; for (i = 0; i < 16; i++) - W[i] = be32_to_cpu(((const __u32 *)in)[i]); + W[i] = be32_to_cpu(((const __be32 *)in)[i]); for (i = 0; i < 64; i++) W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1); diff --git a/mm/bootmem.c b/mm/bootmem.c index f82f7ae..c1330cc 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -33,6 +33,14 @@ EXPORT_SYMBOL(max_pfn); /* This is exported so * dma_get_required_mask(), which uses * it, can be an inline function */ +#ifdef CONFIG_CRASH_DUMP +/* + * If we have booted due to a crash, max_pfn will be a very low value. We need + * to know the amount of memory that the previous kernel used. + */ +unsigned long saved_max_pfn; +#endif + /* return the number of _pages_ that will be allocated for the boot bitmap */ unsigned long __init bootmem_bootmap_pages (unsigned long pages) { @@ -57,7 +65,7 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, pgdat->pgdat_next = pgdat_list; pgdat_list = pgdat; - mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL); + mapsize = ALIGN(mapsize, sizeof(long)); bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); bdata->node_boot_start = (start << PAGE_SHIFT); bdata->node_low_pfn = end; @@ -178,7 +186,7 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, } else preferred = 0; - preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT; + preferred = ALIGN(preferred, align) >> PAGE_SHIFT; preferred += offset; areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; incr = align >> PAGE_SHIFT ? : 1; @@ -219,7 +227,7 @@ found: */ if (align < PAGE_SIZE && bdata->last_offset && bdata->last_pos+1 == start) { - offset = (bdata->last_offset+align-1) & ~(align-1); + offset = ALIGN(bdata->last_offset, align); BUG_ON(offset > PAGE_SIZE); remaining_size = PAGE_SIZE-offset; if (size < remaining_size) { diff --git a/mm/filemap.c b/mm/filemap.c index 7332194..c11418d 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1851,8 +1851,11 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, * i_sem is held, which protects generic_osync_inode() from * livelocking. */ - if (written >= 0 && file->f_flags & O_SYNC) - generic_osync_inode(inode, mapping, OSYNC_METADATA); + if (written >= 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { + int err = generic_osync_inode(inode, mapping, OSYNC_METADATA); + if (err < 0) + written = err; + } if (written == count && !is_sync_kiocb(iocb)) written = -EIOCBQUEUED; return written; @@ -1951,7 +1954,9 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, if (unlikely(nr_segs > 1)) { filemap_set_next_iovec(&cur_iov, &iov_base, status); - buf = cur_iov->iov_base + iov_base; + if (count) + buf = cur_iov->iov_base + + iov_base; } else { iov_base += status; } diff --git a/mm/memory.c b/mm/memory.c index c256175..beabdef 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1139,7 +1139,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, { pgd_t *pgd; unsigned long next; - unsigned long end = addr + size; + unsigned long end = addr + PAGE_ALIGN(size); struct mm_struct *mm = vma->vm_mm; int err; diff --git a/mm/page_io.c b/mm/page_io.c index 667c76d..2e605a1 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -127,7 +127,7 @@ out: return ret; } -#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK) +#ifdef CONFIG_SOFTWARE_SUSPEND /* * A scruffy utility function to read or write an arbitrary swap page * and wait on the I/O. The caller must have a ref on the page. diff --git a/mm/pdflush.c b/mm/pdflush.c index 38ce279..d678195 100644 --- a/mm/pdflush.c +++ b/mm/pdflush.c @@ -105,7 +105,7 @@ static int __pdflush(struct pdflush_work *my_work) spin_unlock_irq(&pdflush_lock); schedule(); - if (try_to_freeze(PF_FREEZE)) { + if (try_to_freeze()) { spin_lock_irq(&pdflush_lock); continue; } diff --git a/mm/vmscan.c b/mm/vmscan.c index 4b8e62a..1fa312a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1216,8 +1216,8 @@ static int kswapd(void *p) order = 0; for ( ; ; ) { unsigned long new_order; - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + + try_to_freeze(); prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE); new_order = pgdat->kswapd_max_order; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 690e88b..3470834 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -1,32 +1,6 @@ # # IP configuration # -choice - prompt "Choose IP: FIB lookup" - depends on INET - default IP_FIB_HASH - -config IP_FIB_HASH - bool "FIB_HASH" - ---help--- - Current FIB is very proven and good enough for most users. - -config IP_FIB_TRIE - bool "FIB_TRIE" - ---help--- - Use new experimental LC-trie as FIB lookup algoritm. - This improves lookup performance - - LC-trie is described in: - - IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson - IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 - An experimental study of compression methods for dynamic tries - Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. - http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ - -endchoice - config IP_MULTICAST bool "IP: multicasting" depends on INET @@ -79,6 +53,44 @@ config IP_ADVANCED_ROUTER If unsure, say N here. +choice + prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)" + depends on IP_ADVANCED_ROUTER + default IP_FIB_HASH + +config IP_FIB_HASH + bool "FIB_HASH" + ---help--- + Current FIB is very proven and good enough for most users. + +config IP_FIB_TRIE + bool "FIB_TRIE" + ---help--- + Use new experimental LC-trie as FIB lookup algoritm. + This improves lookup performance if you have a large + number of routes. + + LC-trie is a longest matching prefix lookup algorithm which + performs better than FIB_HASH for large routing tables. + But, it consumes more memory and is more complex. + + LC-trie is described in: + + IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson + IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 + An experimental study of compression methods for dynamic tries + Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. + http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/ + +endchoice + +# If the user does not enable advanced routing, he gets the safe +# default of the fib-hash algorithm. +config IP_FIB_HASH + bool + depends on !IP_ADVANCED_ROUTER + default y + config IP_MULTIPLE_TABLES bool "IP: policy routing" depends on IP_ADVANCED_ROUTER @@ -433,9 +445,22 @@ config IP_TCPDIAG config IP_TCPDIAG_IPV6 def_bool (IP_TCPDIAG=y && IPV6=y) || (IP_TCPDIAG=m && IPV6) +config TCP_CONG_ADVANCED + bool "TCP: advanced congestion control" + depends on INET + default y + ---help--- + Support for selection of various TCP congestion control + modules. + + Nearly all users can safely say no here, and a safe default + selection will be made (BIC-TCP with new Reno as a fallback). + + If unsure, say N. + # TCP Reno is builtin (required as fallback) menu "TCP congestion control" - depends on INET + depends on TCP_CONG_ADVANCED config TCP_CONG_BIC tristate "Binary Increase Congestion (BIC) control" @@ -523,5 +548,10 @@ config TCP_CONG_SCALABLE endmenu +config TCP_CONG_BIC + boolean + depends on !TCP_CONG_ADVANCED + default y + source "net/ipv4/ipvs/Kconfig" diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c index 2b537f4..dada34a 100644 --- a/net/rxrpc/krxiod.c +++ b/net/rxrpc/krxiod.c @@ -138,7 +138,7 @@ static int rxrpc_krxiod(void *arg) _debug("### End Work"); - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ rxrpc_discard_my_signals(); diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c index 6020c89..1aadd02 100644 --- a/net/rxrpc/krxsecd.c +++ b/net/rxrpc/krxsecd.c @@ -107,7 +107,7 @@ static int rxrpc_krxsecd(void *arg) _debug("### End Inbound Calls"); - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ rxrpc_discard_my_signals(); diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c index 249c2b0..3ac81cd 100644 --- a/net/rxrpc/krxtimod.c +++ b/net/rxrpc/krxtimod.c @@ -90,7 +90,7 @@ static int krxtimod(void *arg) complete_and_exit(&krxtimod_dead, 0); } - try_to_freeze(PF_FREEZE); + try_to_freeze(); /* discard pending signals */ rxrpc_discard_my_signals(); diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 447b89e..7bac249 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -453,10 +453,11 @@ config NET_EMATCH_TEXT tristate "Textsearch" depends on NET_EMATCH select TEXTSEARCH + select TEXTSEARCH_KMP + select TEXTSEARCH_FSM ---help--- Say Y here if you want to be ablt to classify packets based on - textsearch comparisons. Please select the appropriate textsearch - algorithms in the Library section. + textsearch comparisons. To compile this code as a module, choose M here: the module will be called em_text. diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 0590703..56db8f1 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1185,8 +1185,8 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) arg->page_len = (pages-2)*PAGE_SIZE; arg->len = (pages-1)*PAGE_SIZE; arg->tail[0].iov_len = 0; - - try_to_freeze(PF_FREEZE); + + try_to_freeze(); if (signalled()) return -EINTR; @@ -1227,7 +1227,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) schedule_timeout(timeout); - try_to_freeze(PF_FREEZE); + try_to_freeze(); spin_lock_bh(&serv->sv_lock); remove_wait_queue(&rqstp->rq_wait, &wait); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index eca9240..269f217 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -970,7 +970,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) goto out; } - dprintk("RPC: XID %08x read %u bytes\n", + dprintk("RPC: XID %08x read %Zd bytes\n", ntohl(xprt->tcp_xid), r); dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); @@ -1006,7 +1006,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) desc->count -= len; desc->offset += len; xprt->tcp_offset += len; - dprintk("RPC: discarded %u bytes\n", len); + dprintk("RPC: discarded %Zu bytes\n", len); tcp_check_recm(xprt); } diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 8ca7ecd..cb02baa 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -52,7 +52,7 @@ FILEONLY *internalfunctions; FILEONLY *externalfunctions; FILEONLY *symbolsonly; -typedef void FILELINE(char * file, signed char * line); +typedef void FILELINE(char * file, char * line); FILELINE * singlefunctions; FILELINE * entity_system; @@ -148,9 +148,9 @@ struct symfile * filename_exist(char * filename) * Files are separated by tabs. */ void adddep(char * file) { printf("\t%s", file); } -void adddep2(char * file, signed char * line) { line = line; adddep(file); } +void adddep2(char * file, char * line) { line = line; adddep(file); } void noaction(char * line) { line = line; } -void noaction2(char * file, signed char * line) { file = file; line = line; } +void noaction2(char * file, char * line) { file = file; line = line; } /* Echo the line without further action */ void printline(char * line) { printf("%s", line); } @@ -179,8 +179,8 @@ void find_export_symbols(char * filename) perror(real_filename); } while(fgets(line, MAXLINESZ, fp)) { - signed char *p; - signed char *e; + char *p; + char *e; if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) || ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) { /* Skip EXPORT_SYMBOL{_GPL} */ @@ -253,7 +253,7 @@ void extfunc(char * filename) { docfunctions(filename, FUNCTION); } * Call kernel-doc with the following parameters: * kernel-doc -docbook -function function1 [-function function2] */ -void singfunc(char * filename, signed char * line) +void singfunc(char * filename, char * line) { char *vec[200]; /* Enough for specific functions */ int i, idx = 0; @@ -290,7 +290,7 @@ void singfunc(char * filename, signed char * line) void parse_file(FILE *infile) { char line[MAXLINESZ]; - signed char * s; + char * s; while(fgets(line, MAXLINESZ, infile)) { if (line[0] == '!') { s = line + 2; diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 7f42c5d..0b61bea 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -212,23 +212,23 @@ void use_config(char *m, int slen) if (*p == '_') *p = '/'; else - *p = tolower((unsigned char)*p); + *p = tolower((int)*p); } printf(" $(wildcard include/config/%s.h) \\\n", s); } -void parse_config_file(signed char *map, size_t len) +void parse_config_file(char *map, size_t len) { int *end = (int *) (map + len); /* start at +1, so that p can never be < map */ int *m = (int *) map + 1; - signed char *p, *q; + char *p, *q; for (; m < end; m++) { - if (*m == INT_CONF) { p = (signed char *) m ; goto conf; } - if (*m == INT_ONFI) { p = (signed char *) m-1; goto conf; } - if (*m == INT_NFIG) { p = (signed char *) m-2; goto conf; } - if (*m == INT_FIG_) { p = (signed char *) m-3; goto conf; } + if (*m == INT_CONF) { p = (char *) m ; goto conf; } + if (*m == INT_ONFI) { p = (char *) m-1; goto conf; } + if (*m == INT_NFIG) { p = (char *) m-2; goto conf; } + if (*m == INT_FIG_) { p = (char *) m-3; goto conf; } continue; conf: if (p > map + len - 7) @@ -291,9 +291,9 @@ void do_config_file(char *filename) void parse_dep_file(void *map, size_t len) { - signed char *m = map; - signed char *end = m + len; - signed char *p; + char *m = map; + char *end = m + len; + char *p; char s[PATH_MAX]; p = strchr(m, ':'); diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c index 60fc4d8..459c4527 100644 --- a/scripts/basic/split-include.c +++ b/scripts/basic/split-include.c @@ -104,7 +104,7 @@ int main(int argc, const char * argv []) /* Read config lines. */ while (fgets(line, buffer_size, fp_config)) { - const signed char * str_config; + const char * str_config; int is_same; int itarget; diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 70e7264..bc20cab 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -31,14 +31,14 @@ char *defconfig_file; static int indent = 1; static int valid_stdin = 1; static int conf_cnt; -static signed char line[128]; +static char line[128]; static struct menu *rootEntry; static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n"); -static void strip(signed char *str) +static void strip(char *str) { - signed char *p = str; + char *p = str; int l; while ((isspace(*p))) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 2755c45..02f670c 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -27,10 +27,10 @@ const char *conf_confnames[] = { NULL, }; -static char *conf_expand_value(const signed char *in) +static char *conf_expand_value(const char *in) { struct symbol *sym; - const signed char *src; + const char *src; static char res_value[SYMBOL_MAXLENGTH]; char *dst, name[SYMBOL_MAXLENGTH]; diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index e5db10c..457bec2 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -20,6 +20,7 @@ #include <string.h> #include <termios.h> #include <unistd.h> +#include <locale.h> #define LKC_DIRECT_LINK #include "lkc.h" @@ -254,8 +255,8 @@ search_help[] = N_( " USB$ => find all CONFIG_ symbols ending with USB\n" "\n"); -static signed char buf[4096], *bufptr = buf; -static signed char input_buf[4096]; +static char buf[4096], *bufptr = buf; +static char input_buf[4096]; static char filename[PATH_MAX+1] = ".config"; static char *args[1024], **argptr = args; static int indent; diff --git a/security/keys/key.c b/security/keys/key.c index 3304d37..fb89f98 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -980,7 +980,7 @@ void unregister_key_type(struct key_type *ktype) spin_unlock(&key_serial_lock); /* make sure everyone revalidates their keys */ - synchronize_kernel(); + synchronize_rcu(); /* we should now be able to destroy the payloads of all the keys of * this type with impunity */ diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 34db087..9b0369c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -234,7 +234,7 @@ static int install_session_keyring(struct task_struct *tsk, ret = 0; /* we're using RCU on the pointer */ - synchronize_kernel(); + synchronize_rcu(); key_put(old); error: return ret; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 87302a4..17a1189 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1658,9 +1658,8 @@ static int selinux_bprm_secureexec (struct linux_binprm *bprm) static void selinux_bprm_free_security(struct linux_binprm *bprm) { - struct bprm_security_struct *bsec = bprm->security; + kfree(bprm->security); bprm->security = NULL; - kfree(bsec); } extern struct vfsmount *selinuxfs_mount; @@ -2477,6 +2476,17 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, prot = reqprot; #ifndef CONFIG_PPC32 + if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXECUTABLE) && + (vma->vm_start >= vma->vm_mm->start_brk && + vma->vm_end <= vma->vm_mm->brk)) { + /* + * We are making an executable mapping in the brk region. + * This has an additional execheap check. + */ + rc = task_has_perm(current, current, PROCESS__EXECHEAP); + if (rc) + return rc; + } if (vma->vm_file != NULL && vma->anon_vma != NULL && (prot & PROT_EXEC)) { /* * We are making executable a file mapping that has @@ -2488,6 +2498,16 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (rc) return rc; } + if (!vma->vm_file && (prot & PROT_EXEC) && + vma->vm_start <= vma->vm_mm->start_stack && + vma->vm_end >= vma->vm_mm->start_stack) { + /* Attempt to make the process stack executable. + * This has an additional execstack check. + */ + rc = task_has_perm(current, current, PROCESS__EXECSTACK); + if (rc) + return rc; + } #endif return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 8928bb4d..1deb59e 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -70,6 +70,8 @@ S_(SECCLASS_PROCESS, PROCESS__DYNTRANSITION, "dyntransition") S_(SECCLASS_PROCESS, PROCESS__SETCURRENT, "setcurrent") S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem") + S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack") + S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap") S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue") S_(SECCLASS_MSG, MSG__SEND, "send") S_(SECCLASS_MSG, MSG__RECEIVE, "receive") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index bdfce4c..a78b5d5 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -465,6 +465,8 @@ #define PROCESS__DYNTRANSITION 0x00800000UL #define PROCESS__SETCURRENT 0x01000000UL #define PROCESS__EXECMEM 0x02000000UL +#define PROCESS__EXECSTACK 0x04000000UL +#define PROCESS__EXECHEAP 0x08000000UL #define IPC__CREATE 0x00000001UL #define IPC__DESTROY 0x00000002UL diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 0722156..8eb140d 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -951,8 +951,7 @@ static int sel_make_bools(void) u32 sid; /* remove any existing files */ - if (bool_pending_values) - kfree(bool_pending_values); + kfree(bool_pending_values); sel_remove_bools(dir); @@ -997,10 +996,8 @@ static int sel_make_bools(void) out: free_page((unsigned long)page); if (names) { - for (i = 0; i < num; i++) { - if (names[i]) - kfree(names[i]); - } + for (i = 0; i < num; i++) + kfree(names[i]); kfree(names); } return ret; diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index b534411..e2057f5 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -166,16 +166,14 @@ static void cond_list_destroy(struct cond_node *list) void cond_policydb_destroy(struct policydb *p) { - if (p->bool_val_to_struct != NULL) - kfree(p->bool_val_to_struct); + kfree(p->bool_val_to_struct); avtab_destroy(&p->te_cond_avtab); cond_list_destroy(p->cond_list); } int cond_init_bool_indexes(struct policydb *p) { - if (p->bool_val_to_struct) - kfree(p->bool_val_to_struct); + kfree(p->bool_val_to_struct); p->bool_val_to_struct = (struct cond_bool_datum**) kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL); if (!p->bool_val_to_struct) @@ -185,8 +183,7 @@ int cond_init_bool_indexes(struct policydb *p) int cond_destroy_bool(void *key, void *datum, void *p) { - if (key) - kfree(key); + kfree(key); kfree(datum); return 0; } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 14190ef..785c33c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -590,17 +590,12 @@ void policydb_destroy(struct policydb *p) hashtab_destroy(p->symtab[i].table); } - for (i = 0; i < SYM_NUM; i++) { - if (p->sym_val_to_name[i]) - kfree(p->sym_val_to_name[i]); - } + for (i = 0; i < SYM_NUM; i++) + kfree(p->sym_val_to_name[i]); - if (p->class_val_to_struct) - kfree(p->class_val_to_struct); - if (p->role_val_to_struct) - kfree(p->role_val_to_struct); - if (p->user_val_to_struct) - kfree(p->user_val_to_struct); + kfree(p->class_val_to_struct); + kfree(p->role_val_to_struct); + kfree(p->user_val_to_struct); avtab_destroy(&p->te_avtab); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b614914..922bb45 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1705,11 +1705,9 @@ out: err: if (*names) { for (i = 0; i < *len; i++) - if ((*names)[i]) - kfree((*names)[i]); + kfree((*names)[i]); } - if (*values) - kfree(*values); + kfree(*values); goto out; } diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index e537bd6..3b1fafc 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -6,7 +6,7 @@ # Prompt user for primary drivers. config SOUND_BT878 tristate "BT878 audio dma" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME ---help--- Audio DMA support for bt878 based grabber boards. As you might have already noticed, bt878 is listed with two functions in /proc/pci. @@ -22,7 +22,7 @@ config SOUND_BT878 config SOUND_CMPCI tristate "C-Media PCI (CMI8338/8738)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card using the CMI8338 or the CMI8738 chipset. Data on these chips are available at @@ -61,7 +61,7 @@ config SOUND_CMPCI_JOYSTICK config SOUND_EMU10K1 tristate "Creative SBLive! (EMU10K1)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI ---help--- Say Y or M if you have a PCI sound card using the EMU10K1 chipset, such as the Creative SBLive!, SB PCI512 or Emu-APS. @@ -87,7 +87,7 @@ config MIDI_EMU10K1 config SOUND_FUSION tristate "Crystal SoundFusion (CS4280/461x)" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help This module drives the Crystal SoundFusion devices (CS4280/46xx series) when wired as native sound drivers with AC97 codecs. If @@ -95,14 +95,14 @@ config SOUND_FUSION config SOUND_CS4281 tristate "Crystal Sound CS4281" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help Picture and feature list at <http://www.pcbroker.com/crystal4281.html>. config SOUND_BCM_CS4297A tristate "Crystal Sound CS4297a (for Swarm)" - depends on SOUND_PRIME!=n && SIBYTE_SWARM && SOUND + depends on SOUND_PRIME && SIBYTE_SWARM help The BCM91250A has a Crystal CS4297a on synchronous serial port B (in addition to the DB-9 serial port). Say Y or M @@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A config SOUND_ES1370 tristate "Ensoniq AudioPCI (ES1370)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find @@ -125,7 +125,7 @@ config SOUND_ES1370 config SOUND_ES1371 tristate "Creative Ensoniq AudioPCI 97 (ES1371)" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if @@ -138,7 +138,7 @@ config SOUND_ES1371 config SOUND_ESSSOLO1 tristate "ESS Technology Solo1" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the ESS Technology Solo1 chip. To find out if your sound card uses a @@ -149,7 +149,7 @@ config SOUND_ESSSOLO1 config SOUND_MAESTRO tristate "ESS Maestro, Maestro2, Maestro2E driver" - depends on SOUND_PRIME!=n && SOUND && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a sound system driven by ESS's Maestro line of PCI sound chips. These include the Maestro 1, Maestro 2, and @@ -158,28 +158,28 @@ config SOUND_MAESTRO config SOUND_MAESTRO3 tristate "ESS Maestro3/Allegro driver (EXPERIMENTAL)" - depends on SOUND_PRIME!=n && SOUND && PCI && EXPERIMENTAL + depends on SOUND_PRIME && PCI && EXPERIMENTAL help Say Y or M if you have a sound system driven by ESS's Maestro 3 PCI sound chip. config SOUND_ICH tristate "Intel ICH (i8xx) audio support" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Support for integral audio in Intel's I/O Controller Hub (ICH) chipset, as used on the 810/820/840 motherboards. config SOUND_HARMONY tristate "PA Harmony audio driver" - depends on GSC_LASI && SOUND_PRIME!=n + depends on GSC_LASI && SOUND_PRIME help Say 'Y' or 'M' to include support for Harmony soundchip on HP 712, 715/new and many other GSC based machines. config SOUND_SONICVIBES tristate "S3 SonicVibes" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help Say Y or M if you have a PCI sound card utilizing the S3 SonicVibes chipset. To find out if your sound card uses a @@ -190,7 +190,7 @@ config SOUND_SONICVIBES config SOUND_VWSND tristate "SGI Visual Workstation Sound" - depends on SOUND_PRIME!=n && X86_VISWS && SOUND + depends on SOUND_PRIME && X86_VISWS help Say Y or M if you have an SGI Visual Workstation and you want to be able to use its on-board audio. Read @@ -199,18 +199,18 @@ config SOUND_VWSND config SOUND_HAL2 tristate "SGI HAL2 sound (EXPERIMENTAL)" - depends on SOUND_PRIME!=n && SOUND && SGI_IP22 && EXPERIMENTAL + depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL help Say Y or M if you have an SGI Indy system and want to be able to use it's on-board A2 audio system. config SOUND_IT8172 tristate "IT8172G Sound" - depends on SOUND_PRIME!=n && (MIPS_ITE8172 || MIPS_IVR) && SOUND + depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR) config SOUND_VRC5477 tristate "NEC Vrc5477 AC97 sound" - depends on SOUND_PRIME!=n && DDB5477 && SOUND + depends on SOUND_PRIME && DDB5477 help Say Y here to enable sound support for the NEC Vrc5477 chip, an integrated, multi-function controller chip for MIPS CPUs. Works @@ -218,15 +218,15 @@ config SOUND_VRC5477 config SOUND_AU1000 tristate "Au1000 Sound" - depends on SOUND_PRIME!=n && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SOUND + depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) config SOUND_AU1550_AC97 tristate "Au1550 AC97 Sound" - depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND + depends on SOUND_PRIME && SOC_AU1550 config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME ---help--- Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 @@ -267,7 +267,7 @@ config SOUND_TRIDENT config SOUND_MSNDCLAS tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE) + depends on SOUND_PRIME && (m || !STANDALONE) help Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or Monterey (not for the Pinnacle or Fiji). @@ -331,7 +331,7 @@ config MSNDCLAS_IO config SOUND_MSNDPIN tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" - depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE) + depends on SOUND_PRIME && (m || !STANDALONE) help Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. See <file:Documentation/sound/oss/MultiSound> for important information @@ -492,7 +492,7 @@ config MSND_FIFOSIZE config SOUND_VIA82CXXX tristate "VIA 82C686 Audio Codec" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Say Y here to include support for the audio codec found on VIA 82Cxxx-based chips. Typically these are built into a motherboard. @@ -512,7 +512,7 @@ config MIDI_VIA82CXXX config SOUND_OSS tristate "OSS sound modules" - depends on SOUND_PRIME!=n && SOUND + depends on SOUND_PRIME help OSS is the Open Sound System suite of sound card drivers. They make sound programming easier since they provide a common API. Say Y or @@ -1077,7 +1077,7 @@ config SOUND_WAVEARTIST config SOUND_TVMIXER tristate "TV card (bt848) mixer support" - depends on SOUND_PRIME!=n && SOUND && I2C + depends on SOUND_PRIME && I2C help Support for audio mixer facilities on the BT848 TV frame-grabber card. @@ -1088,11 +1088,11 @@ config SOUND_KAHLUA config SOUND_ALI5455 tristate "ALi5455 audio support" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI config SOUND_FORTE tristate "ForteMedia FM801 driver" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you want driver support for the ForteMedia FM801 PCI audio controller (Abit AU10, Genius Sound Maker, HP Workstation @@ -1100,7 +1100,7 @@ config SOUND_FORTE config SOUND_RME96XX tristate "RME Hammerfall (RME96XX) support" - depends on SOUND_PRIME!=n && PCI + depends on SOUND_PRIME && PCI help Say Y or M if you have a Hammerfall or Hammerfall light multichannel card from RME. If you want to access advanced @@ -1108,11 +1108,11 @@ config SOUND_RME96XX config SOUND_AD1980 tristate "AD1980 front/back switch plugin" - depends on SOUND_PRIME!=n + depends on SOUND_PRIME config SOUND_SH_DAC_AUDIO tristate "SuperH DAC audio support" - depends on SOUND_PRIME!=n && SOUND && CPU_SH3 + depends on SOUND_PRIME && CPU_SH3 config SOUND_SH_DAC_AUDIO_CHANNEL int " DAC channel" diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c index 22dae5d..95586de 100644 --- a/sound/oss/ad1816.c +++ b/sound/oss/ad1816.c @@ -592,7 +592,7 @@ typedef struct mixer_def mixer_ent; {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}} -mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = { +static mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = { MIX_ENT(SOUND_MIXER_VOLUME, 14, 1, 8, 5, 14, 1, 0, 5), MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 4384dac..7c835ab 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -2178,8 +2178,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int if (devc != NULL) { - if(audio_devs[dev]->portc!=NULL) - kfree(audio_devs[dev]->portc); + kfree(audio_devs[dev]->portc); release_region(devc->base, 4); if (!share_dma) diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c index b767c62..2cfd214 100644 --- a/sound/oss/ad1889.c +++ b/sound/oss/ad1889.c @@ -277,8 +277,7 @@ static void ad1889_free_dev(ad1889_dev_t *dev) for (j = 0; j < AD_MAX_STATES; j++) { dmabuf = &dev->state[j].dmabuf; - if (dmabuf->rawbuf != NULL) - kfree(dmabuf->rawbuf); + kfree(dmabuf->rawbuf); } kfree(dev); diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c index 34720e6..74dcca7 100644 --- a/sound/oss/cmpci.c +++ b/sound/oss/cmpci.c @@ -123,6 +123,7 @@ #include <linux/smp_lock.h> #include <linux/bitops.h> #include <linux/wait.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/page.h> @@ -3058,7 +3059,7 @@ static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id return -ENODEV; if (pcidev->irq == 0) return -ENODEV; - i = pci_set_dma_mask(pcidev, 0xffffffff); + i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); if (i) { printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n"); return i; diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index 5281b88..3310866 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -671,14 +671,10 @@ static void PMacIrqCleanup(void) release_OF_resource(awacs_node, 1); release_OF_resource(awacs_node, 2); - if (awacs_tx_cmd_space) - kfree(awacs_tx_cmd_space); - if (awacs_rx_cmd_space) - kfree(awacs_rx_cmd_space); - if (beep_dbdma_cmd_space) - kfree(beep_dbdma_cmd_space); - if (beep_buf) - kfree(beep_buf); + kfree(awacs_tx_cmd_space); + kfree(awacs_rx_cmd_space); + kfree(beep_dbdma_cmd_space); + kfree(beep_buf); #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&awacs_sleep_notifier); #endif @@ -2301,8 +2297,7 @@ if (count <= 0) #endif if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) { - if (awacs_tx_cmd_space) - kfree(awacs_tx_cmd_space); + kfree(awacs_tx_cmd_space); number_of_tx_cmd_buffers = 0; /* we need nbufs + 1 (for the loop) and we should request + 1 @@ -2360,8 +2355,7 @@ if (count <= 0) #endif if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) { - if (awacs_rx_cmd_space) - kfree(awacs_rx_cmd_space); + kfree(awacs_rx_cmd_space); number_of_rx_cmd_buffers = 0; /* we need nbufs + 1 (for the loop) and we should request + 1 again @@ -2805,7 +2799,7 @@ __init setup_beep(void) beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); if (beep_buf == NULL) { printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n"); - if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ; + kfree(beep_dbdma_cmd_space) ; return -ENOMEM ; } return 0 ; diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c index 33dea3d..b40b5f9 100644 --- a/sound/oss/emu10k1/midi.c +++ b/sound/oss/emu10k1/midi.c @@ -523,10 +523,8 @@ void emu10k1_seq_midi_close(int dev) card = midi_devs[dev]->devc; emu10k1_mpuout_close(card); - if (card->seq_mididev) { - kfree(card->seq_mididev); - card->seq_mididev = NULL; - } + kfree(card->seq_mididev); + card->seq_mididev = NULL; } int emu10k1_seq_midi_out(int dev, unsigned char midi_byte) diff --git a/sound/oss/emu10k1/passthrough.c b/sound/oss/emu10k1/passthrough.c index 4094be5..4e3baca 100644 --- a/sound/oss/emu10k1/passthrough.c +++ b/sound/oss/emu10k1/passthrough.c @@ -213,8 +213,7 @@ void emu10k1_pt_stop(struct emu10k1_card *card) sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]); } pt->state = PT_STATE_INACTIVE; - if(pt->buf) - kfree(pt->buf); + kfree(pt->buf); } } diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c index 056091c..886f61c 100644 --- a/sound/oss/es1370.c +++ b/sound/oss/es1370.c @@ -156,6 +156,7 @@ #include <linux/spinlock.h> #include <linux/gameport.h> #include <linux/wait.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/page.h> @@ -2569,7 +2570,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic return -ENODEV; if (pcidev->irq == 0) return -ENODEV; - i = pci_set_dma_mask(pcidev, 0xffffffff); + i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); if (i) { printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); return i; diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c index a50fdda..9266b77 100644 --- a/sound/oss/es1371.c +++ b/sound/oss/es1371.c @@ -128,6 +128,7 @@ #include <linux/ac97_codec.h> #include <linux/gameport.h> #include <linux/wait.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/page.h> @@ -2804,7 +2805,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic return -ENODEV; if (pcidev->irq == 0) return -ENODEV; - i = pci_set_dma_mask(pcidev, 0xffffffff); + i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); if (i) { printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); return i; diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c index 6b3b9a9..fb09065 100644 --- a/sound/oss/esssolo1.c +++ b/sound/oss/esssolo1.c @@ -104,6 +104,7 @@ #include <linux/smp_lock.h> #include <linux/gameport.h> #include <linux/wait.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/page.h> @@ -2326,7 +2327,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device * to 24 bits first, then 32 bits (playback only) if that fails. */ if (pci_set_dma_mask(pcidev, 0x00ffffff) && - pci_set_dma_mask(pcidev, 0xffffffff)) { + pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) { printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); return -ENODEV; } diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c index 52d2db4..3dce504 100644 --- a/sound/oss/maestro.c +++ b/sound/oss/maestro.c @@ -2356,7 +2356,7 @@ ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) } rec_return_free: - if(combbuf) kfree(combbuf); + kfree(combbuf); return ret; } diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index b66f53f..0aac54c 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -1240,8 +1240,7 @@ void unload_mpu401(struct address_info *hw_config) p=mpu401_synth_operations[n]; sound_unload_mididev(n); sound_unload_timerdev(hw_config->slots[2]); - if(p) - kfree(p); + kfree(p); } } diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h index eae7d99..21e07b5 100644 --- a/sound/oss/nm256.h +++ b/sound/oss/nm256.h @@ -128,9 +128,6 @@ struct nm256_info struct nm256_info *next_card; }; -/* Debug flag--bigger numbers mean more output. */ -extern int nm256_debug; - /* The BIOS signature. */ #define NM_SIGNATURE 0x4e4d0000 /* Signature mask. */ @@ -284,7 +281,7 @@ nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset, } /* Returns a non-zero value if we should use the coefficient cache. */ -extern int nm256_cachedCoefficients (struct nm256_info *card); +static int nm256_cachedCoefficients (struct nm256_info *card); #endif diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c index f9166e1..6697006 100644 --- a/sound/oss/nm256_audio.c +++ b/sound/oss/nm256_audio.c @@ -28,12 +28,13 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include "sound_config.h" -#include "nm256.h" -#include "nm256_coeff.h" -int nm256_debug; +static int nm256_debug; static int force_load; +#include "nm256.h" +#include "nm256_coeff.h" + /* * The size of the playback reserve. When the playback buffer has less * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new @@ -138,7 +139,7 @@ static int usecache; static int buffertop; /* Check to see if we're using the bank of cached coefficients. */ -int +static int nm256_cachedCoefficients (struct nm256_info *card) { return usecache; diff --git a/sound/oss/nm256_coeff.h b/sound/oss/nm256_coeff.h index 0ceecc2..6fc07f3 100644 --- a/sound/oss/nm256_coeff.h +++ b/sound/oss/nm256_coeff.h @@ -4650,7 +4650,7 @@ nm256_loadAllCoefficients (struct nm256_info *card) card->coeffsCurrent = 1; } -void +static void nm256_loadCoefficient (struct nm256_info *card, int which, int number) { static u16 addrs[3] = { 0x1c, 0x21c, 0x408 }; diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c index b4278ee..7609c68 100644 --- a/sound/oss/rme96xx.c +++ b/sound/oss/rme96xx.c @@ -1750,9 +1750,7 @@ static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wa static struct file_operations rme96xx_audio_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) .owner = THIS_MODULE, -#endif .read = rme96xx_read, .write = rme96xx_write, .poll = rme96xx_poll, @@ -1852,9 +1850,7 @@ static int rme96xx_mixer_release(struct inode *inode, struct file *file) } static /*const*/ struct file_operations rme96xx_mixer_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) .owner = THIS_MODULE, -#endif .ioctl = rme96xx_mixer_ioctl, .open = rme96xx_mixer_open, .release = rme96xx_mixer_release, diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index ce359e6..5f955e3 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -915,8 +915,8 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu) } else release_region(hw_config->io_base, 16); - if(detected_devc) - kfree(detected_devc); + + kfree(detected_devc); } /* diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c index 50ca646..9ed5211 100644 --- a/sound/oss/sscape.c +++ b/sound/oss/sscape.c @@ -991,7 +991,6 @@ static void __init sscape_pnp_init_hw(sscape_info* devc) unsigned i; static char code_file_name[23] = "/sndscape/sndscape.cox"; - int sscape_sb_enable = 0; int sscape_joystic_enable = 0x7f; int sscape_mic_enable = 0; int sscape_ext_midi = 0; @@ -1015,14 +1014,9 @@ static void __init sscape_pnp_init_hw(sscape_info* devc) sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); sscape_write( devc, 3, ( devc -> dma << 4) | 0x80); - if ( sscape_sb_enable ) - sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq); - else - sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); + sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0); - if ( sscape_sb_enable ) - i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07; if (sscape_joystic_enable) i |= 8; sscape_write (devc, 9, i); diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c index 077b767..a7ef04f 100644 --- a/sound/oss/v_midi.c +++ b/sound/oss/v_midi.c @@ -39,8 +39,6 @@ static void *midi_mem = NULL; */ -void (*midi_input_intr) (int dev, unsigned char data); - static int v_midi_open (int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev) diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c index cce1278..b92ba89 100644 --- a/sound/oss/wavfront.c +++ b/sound/oss/wavfront.c @@ -151,11 +151,11 @@ static int (*midi_load_patch) (int devno, int format, const char __user *addr, /*** Module-accessible parameters ***************************************/ -int wf_raw; /* we normally check for "raw state" to firmware - loading. if set, then during driver loading, the - state of the board is ignored, and we reset the - board and load the firmware anyway. - */ +static int wf_raw; /* we normally check for "raw state" to firmware + loading. if set, then during driver loading, the + state of the board is ignored, and we reset the + board and load the firmware anyway. + */ static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in whatever state it is when the driver is loaded. @@ -2911,7 +2911,7 @@ int __init detect_wffx (void) return 0; } -void +static void wffx_mute (int onoff) { |