aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS11
-rw-r--r--Documentation/CodingStyle4
-rw-r--r--Documentation/crypto/api-intro.txt3
-rw-r--r--Documentation/driver-model/bus.txt74
-rw-r--r--Documentation/filesystems/ext2.txt34
-rw-r--r--Documentation/filesystems/ext3.txt72
-rw-r--r--Documentation/filesystems/proc.txt26
-rw-r--r--Documentation/i2c/sysfs-interface2
-rw-r--r--Documentation/kernel-parameters.txt16
-rw-r--r--Documentation/laptop-mode.txt2
-rw-r--r--Documentation/sched-domains.txt27
-rw-r--r--Documentation/sched-stats.txt153
-rw-r--r--Documentation/sysctl/kernel.txt18
-rw-r--r--Documentation/x86_64/boot-options.txt24
-rw-r--r--MAINTAINERS44
-rw-r--r--Makefile4
-rw-r--r--arch/alpha/kernel/process.c3
-rw-r--r--arch/alpha/kernel/signal.c17
-rw-r--r--arch/alpha/kernel/smp.c16
-rw-r--r--arch/alpha/kernel/time.c2
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S5
-rw-r--r--arch/alpha/mm/numa.c2
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/common/dmabounce.c34
-rw-r--r--arch/arm/common/sa1111.c13
-rw-r--r--arch/arm/kernel/armksyms.c1
-rw-r--r--arch/arm/kernel/signal.c4
-rw-r--r--arch/arm/kernel/sys_arm.c9
-rw-r--r--arch/arm/kernel/vmlinux.lds.S3
-rw-r--r--arch/arm/mach-s3c2410/clock.c14
-rw-r--r--arch/arm/mach-s3c2410/devs.c7
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c24
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c23
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c16
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c23
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c56
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.h15
-rw-r--r--arch/arm/mm/init.c2
-rw-r--r--arch/arm/nwfpe/fpa11_cpdt.c10
-rw-r--r--arch/arm/oprofile/op_model_xscale.c21
-rw-r--r--arch/arm26/kernel/signal.c4
-rw-r--r--arch/arm26/kernel/sys_arm.c2
-rw-r--r--arch/arm26/kernel/vmlinux-arm26-xip.lds.in3
-rw-r--r--arch/arm26/kernel/vmlinux-arm26.lds.in3
-rw-r--r--arch/arm26/mm/init.c4
-rw-r--r--arch/cris/arch-v10/kernel/process.c2
-rw-r--r--arch/cris/arch-v10/kernel/signal.c8
-rw-r--r--arch/cris/arch-v10/mm/init.c2
-rw-r--r--arch/cris/arch-v10/vmlinux.lds.S3
-rw-r--r--arch/h8300/kernel/process.c2
-rw-r--r--arch/h8300/kernel/signal.c8
-rw-r--r--arch/h8300/kernel/vmlinux.lds.S3
-rw-r--r--arch/i386/Kconfig.debug12
-rw-r--r--arch/i386/kernel/Makefile6
-rw-r--r--arch/i386/kernel/apic.c12
-rw-r--r--arch/i386/kernel/apm.c2
-rw-r--r--arch/i386/kernel/cpu/common.c2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c236
-rw-r--r--arch/i386/kernel/cpu/intel.c76
-rw-r--r--arch/i386/kernel/cpu/proc.c4
-rw-r--r--arch/i386/kernel/doublefault.c2
-rw-r--r--arch/i386/kernel/io_apic.c2
-rw-r--r--arch/i386/kernel/process.c9
-rw-r--r--arch/i386/kernel/signal.c22
-rw-r--r--arch/i386/kernel/smpboot.c230
-rw-r--r--arch/i386/kernel/vmlinux.lds.S6
-rw-r--r--arch/i386/kernel/vsyscall.lds.S (renamed from arch/i386/kernel/vsyscall.lds)4
-rw-r--r--arch/i386/mach-es7000/es7000.h2
-rw-r--r--arch/i386/mach-es7000/es7000plat.c2
-rw-r--r--arch/i386/mach-generic/bigsmp.c28
-rw-r--r--arch/i386/mach-voyager/voyager_smp.c17
-rw-r--r--arch/i386/mm/Makefile2
-rw-r--r--arch/i386/mm/discontig.c8
-rw-r--r--arch/i386/mm/mmap.c71
-rw-r--r--arch/i386/pci/i386.c2
-rw-r--r--arch/ia64/hp/sim/simserial.c2
-rw-r--r--arch/ia64/ia32/ia32_entry.S2
-rw-r--r--arch/ia64/ia32/ia32_signal.c8
-rw-r--r--arch/ia64/kernel/asm-offsets.c5
-rw-r--r--arch/ia64/kernel/entry.S4
-rw-r--r--arch/ia64/kernel/signal.c64
-rw-r--r--arch/ia64/kernel/smpboot.c30
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S6
-rw-r--r--arch/ia64/mm/contig.c5
-rw-r--r--arch/ia64/mm/discontig.c3
-rw-r--r--arch/ia64/mm/init.c10
-rw-r--r--arch/m68k/kernel/process.c2
-rw-r--r--arch/m68k/kernel/signal.c8
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds3
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds3
-rw-r--r--arch/m68knommu/kernel/process.c2
-rw-r--r--arch/m68knommu/kernel/signal.c8
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S3
-rw-r--r--arch/mips/kernel/irixsig.c4
-rw-r--r--arch/mips/kernel/signal.c8
-rw-r--r--arch/mips/kernel/signal32.c8
-rw-r--r--arch/mips/kernel/signal_n32.c4
-rw-r--r--arch/mips/kernel/smp.c22
-rw-r--r--arch/mips/kernel/syscall.c2
-rw-r--r--arch/mips/kernel/vmlinux.lds.S3
-rw-r--r--arch/mips/sgi-ip27/ip27-memory.c2
-rw-r--r--arch/parisc/kernel/hardware.c2
-rw-r--r--arch/parisc/kernel/process.c2
-rw-r--r--arch/parisc/kernel/smp.c23
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S3
-rw-r--r--arch/parisc/mm/init.c2
-rw-r--r--arch/ppc/8xx_io/uart.c2
-rw-r--r--arch/ppc/Kconfig14
-rw-r--r--arch/ppc/Kconfig.debug12
-rw-r--r--arch/ppc/amiga/config.c3
-rw-r--r--arch/ppc/boot/simple/misc-embedded.c8
-rw-r--r--arch/ppc/configs/mvme5100_defconfig403
-rw-r--r--arch/ppc/kernel/cpu_setup_6xx.S6
-rw-r--r--arch/ppc/kernel/cputable.c2
-rw-r--r--arch/ppc/kernel/idle.c34
-rw-r--r--arch/ppc/kernel/misc.S21
-rw-r--r--arch/ppc/kernel/pci.c9
-rw-r--r--arch/ppc/kernel/ppc_htab.c33
-rw-r--r--arch/ppc/kernel/process.c3
-rw-r--r--arch/ppc/kernel/setup.c4
-rw-r--r--arch/ppc/kernel/signal.c31
-rw-r--r--arch/ppc/kernel/smp.c9
-rw-r--r--arch/ppc/kernel/vmlinux.lds.S3
-rw-r--r--arch/ppc/math-emu/op-common.h1
-rw-r--r--arch/ppc/platforms/4xx/ebony.c4
-rw-r--r--arch/ppc/platforms/4xx/ocotea.c4
-rw-r--r--arch/ppc/platforms/85xx/mpc8540_ads.c4
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.c4
-rw-r--r--arch/ppc/platforms/85xx/sbc8560.c3
-rw-r--r--arch/ppc/platforms/Makefile8
-rw-r--r--arch/ppc/platforms/chrp_setup.c7
-rw-r--r--arch/ppc/platforms/est8260.h3
-rw-r--r--arch/ppc/platforms/est8260_setup.c65
-rw-r--r--arch/ppc/platforms/k2.c4
-rw-r--r--arch/ppc/platforms/lopec.c (renamed from arch/ppc/platforms/lopec_setup.c)162
-rw-r--r--arch/ppc/platforms/lopec.h (renamed from arch/ppc/platforms/lopec_serial.h)0
-rw-r--r--arch/ppc/platforms/lopec_pci.c99
-rw-r--r--arch/ppc/platforms/mcpn765.c6
-rw-r--r--arch/ppc/platforms/mcpn765.h50
-rw-r--r--arch/ppc/platforms/mcpn765_serial.h64
-rw-r--r--arch/ppc/platforms/mvme5100.c (renamed from arch/ppc/platforms/mvme5100_setup.c)199
-rw-r--r--arch/ppc/platforms/mvme5100.h25
-rw-r--r--arch/ppc/platforms/mvme5100_pci.c121
-rw-r--r--arch/ppc/platforms/mvme5100_serial.h54
-rw-r--r--arch/ppc/platforms/pcore.c4
-rw-r--r--arch/ppc/platforms/pmac_setup.c3
-rw-r--r--arch/ppc/platforms/powerpmc250.h18
-rw-r--r--arch/ppc/platforms/powerpmc250_serial.h40
-rw-r--r--arch/ppc/platforms/pplus.c2
-rw-r--r--arch/ppc/platforms/pq2ads.c26
-rw-r--r--arch/ppc/platforms/pq2ads.h4
-rw-r--r--arch/ppc/platforms/pq2ads_setup.c66
-rw-r--r--arch/ppc/platforms/prep_pci.c176
-rw-r--r--arch/ppc/platforms/prep_setup.c218
-rw-r--r--arch/ppc/platforms/prpmc750.c4
-rw-r--r--arch/ppc/platforms/prpmc750.h26
-rw-r--r--arch/ppc/platforms/prpmc750_serial.h43
-rw-r--r--arch/ppc/platforms/prpmc800.c4
-rw-r--r--arch/ppc/platforms/prpmc800.h28
-rw-r--r--arch/ppc/platforms/prpmc800_serial.h49
-rw-r--r--arch/ppc/platforms/residual.c133
-rw-r--r--arch/ppc/platforms/rpx8260.c65
-rw-r--r--arch/ppc/platforms/rpx8260.h7
-rw-r--r--arch/ppc/platforms/sandpoint.c4
-rw-r--r--arch/ppc/platforms/sbc82xx.c39
-rw-r--r--arch/ppc/platforms/sbc82xx.h4
-rw-r--r--arch/ppc/platforms/spruce.c5
-rw-r--r--arch/ppc/platforms/tqm8260.h4
-rw-r--r--arch/ppc/platforms/tqm8260_setup.c41
-rw-r--r--arch/ppc/syslib/Makefile4
-rw-r--r--arch/ppc/syslib/cpm2_pic.c25
-rw-r--r--arch/ppc/syslib/cpm2_pic.h8
-rw-r--r--arch/ppc/syslib/hawk_common.c32
-rw-r--r--arch/ppc/syslib/m8260_pci.h1
-rw-r--r--arch/ppc/syslib/m8260_setup.c84
-rw-r--r--arch/ppc/syslib/m8xx_setup.c6
-rw-r--r--arch/ppc/syslib/m8xx_wdt.c99
-rw-r--r--arch/ppc/syslib/m8xx_wdt.h16
-rw-r--r--arch/ppc/syslib/ppc4xx_setup.c4
-rw-r--r--arch/ppc64/Kconfig.debug12
-rw-r--r--arch/ppc64/kernel/head.S14
-rw-r--r--arch/ppc64/kernel/pSeries_lpar.c24
-rw-r--r--arch/ppc64/kernel/process.c2
-rw-r--r--arch/ppc64/kernel/signal.c15
-rw-r--r--arch/ppc64/kernel/signal32.c32
-rw-r--r--arch/ppc64/kernel/smp.c233
-rw-r--r--arch/ppc64/kernel/vmlinux.lds.S6
-rw-r--r--arch/ppc64/mm/Makefile2
-rw-r--r--arch/ppc64/mm/hash_low.S6
-rw-r--r--arch/ppc64/mm/hash_utils.c31
-rw-r--r--arch/ppc64/mm/init.c2
-rw-r--r--arch/ppc64/mm/mmap.c86
-rw-r--r--arch/ppc64/mm/numa.c11
-rw-r--r--arch/s390/defconfig4
-rw-r--r--arch/s390/kernel/compat_linux.c5
-rw-r--r--arch/s390/kernel/compat_signal.c17
-rw-r--r--arch/s390/kernel/process.c2
-rw-r--r--arch/s390/kernel/signal.c25
-rw-r--r--arch/s390/kernel/smp.c8
-rw-r--r--arch/s390/kernel/vmlinux.lds.S3
-rw-r--r--arch/s390/kernel/vtime.c2
-rw-r--r--arch/s390/mm/Makefile2
-rw-r--r--arch/s390/mm/mmap.c83
-rw-r--r--arch/sh/kernel/process.c2
-rw-r--r--arch/sh/kernel/signal.c8
-rw-r--r--arch/sh/kernel/smp.c9
-rw-r--r--arch/sh/kernel/vmlinux.lds.S3
-rw-r--r--arch/sh/mm/init.c6
-rw-r--r--arch/sh64/kernel/process.c2
-rw-r--r--arch/sh64/kernel/signal.c8
-rw-r--r--arch/sh64/kernel/vmlinux.lds.S3
-rw-r--r--arch/sh64/mm/init.c4
-rw-r--r--arch/sparc/kernel/process.c2
-rw-r--r--arch/sparc/kernel/signal.c35
-rw-r--r--arch/sparc/kernel/sun4d_smp.c11
-rw-r--r--arch/sparc/kernel/sun4m_smp.c11
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S3
-rw-r--r--arch/sparc/mm/srmmu.c2
-rw-r--r--arch/sparc/mm/sun4c.c2
-rw-r--r--arch/sparc64/defconfig25
-rw-r--r--arch/sparc64/kernel/process.c2
-rw-r--r--arch/sparc64/kernel/signal.c31
-rw-r--r--arch/sparc64/kernel/signal32.c57
-rw-r--r--arch/sparc64/kernel/smp.c9
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S3
-rw-r--r--arch/sparc64/mm/init.c2
-rw-r--r--arch/um/Kconfig38
-rw-r--r--arch/um/Kconfig.debug4
-rw-r--r--arch/um/Kconfig_block4
-rw-r--r--arch/um/Kconfig_char57
-rw-r--r--arch/um/Kconfig_net70
-rw-r--r--arch/um/Makefile117
-rw-r--r--arch/um/Makefile-i38623
-rw-r--r--arch/um/Makefile-skas6
-rw-r--r--arch/um/config.release1
-rw-r--r--arch/um/defconfig272
-rw-r--r--arch/um/drivers/Makefile18
-rw-r--r--arch/um/drivers/chan_kern.c63
-rw-r--r--arch/um/drivers/chan_user.c104
-rw-r--r--arch/um/drivers/cow.h41
-rw-r--r--arch/um/drivers/cow_sys.h48
-rw-r--r--arch/um/drivers/cow_user.c375
-rw-r--r--arch/um/drivers/daemon_user.c26
-rw-r--r--arch/um/drivers/fd.c3
-rw-r--r--arch/um/drivers/harddog_user.c62
-rw-r--r--arch/um/drivers/hostaudio_kern.c154
-rw-r--r--arch/um/drivers/hostaudio_user.c149
-rw-r--r--arch/um/drivers/line.c152
-rw-r--r--arch/um/drivers/mcast_user.c16
-rw-r--r--arch/um/drivers/mconsole_kern.c140
-rw-r--r--arch/um/drivers/mconsole_user.c25
-rw-r--r--arch/um/drivers/mmapper_kern.c5
-rw-r--r--arch/um/drivers/net_kern.c89
-rw-r--r--arch/um/drivers/net_user.c49
-rw-r--r--arch/um/drivers/null.c1
-rw-r--r--arch/um/drivers/port_kern.c17
-rw-r--r--arch/um/drivers/port_user.c31
-rw-r--r--arch/um/drivers/pty.c22
-rw-r--r--arch/um/drivers/slip_user.c75
-rw-r--r--arch/um/drivers/slirp_user.c23
-rw-r--r--arch/um/drivers/ssl.c49
-rw-r--r--arch/um/drivers/stdio_console.c56
-rw-r--r--arch/um/drivers/tty.c4
-rw-r--r--arch/um/drivers/ubd_kern.c602
-rw-r--r--arch/um/drivers/ubd_user.c497
-rw-r--r--arch/um/drivers/xterm.c21
-rw-r--r--arch/um/drivers/xterm_kern.c12
-rw-r--r--arch/um/dyn.lds.S15
-rw-r--r--arch/um/include/2_5compat.h14
-rw-r--r--arch/um/include/hostaudio.h48
-rw-r--r--arch/um/include/irq_kern.h28
-rw-r--r--arch/um/include/kern_util.h11
-rw-r--r--arch/um/include/line.h4
-rw-r--r--arch/um/include/mconsole.h6
-rw-r--r--arch/um/include/mem.h15
-rw-r--r--arch/um/include/mem_kern.h30
-rw-r--r--arch/um/include/mem_user.h31
-rw-r--r--arch/um/include/os.h53
-rw-r--r--arch/um/include/signal_user.h2
-rw-r--r--arch/um/include/skas_ptrace.h2
-rw-r--r--arch/um/include/sysdep-i386/checksum.h1
-rw-r--r--arch/um/include/sysdep-i386/frame_user.h28
-rw-r--r--arch/um/include/sysdep-i386/sigcontext.h4
-rw-r--r--arch/um/include/sysdep-i386/syscalls.h59
-rw-r--r--arch/um/include/ubd_user.h9
-rw-r--r--arch/um/include/um_uaccess.h51
-rw-r--r--arch/um/include/user.h3
-rw-r--r--arch/um/include/user_util.h12
-rw-r--r--arch/um/kernel/Makefile48
-rw-r--r--arch/um/kernel/config.c.in4
-rw-r--r--arch/um/kernel/exec_kern.c5
-rw-r--r--arch/um/kernel/frame.c11
-rw-r--r--arch/um/kernel/frame_kern.c6
-rw-r--r--arch/um/kernel/helper.c58
-rw-r--r--arch/um/kernel/init_task.c17
-rw-r--r--arch/um/kernel/initrd_user.c13
-rw-r--r--arch/um/kernel/irq.c106
-rw-r--r--arch/um/kernel/irq_user.c37
-rw-r--r--arch/um/kernel/ksyms.c55
-rw-r--r--arch/um/kernel/main.c (renamed from arch/um/main.c)71
-rw-r--r--arch/um/kernel/mem.c657
-rw-r--r--arch/um/kernel/mem_user.c222
-rw-r--r--arch/um/kernel/physmem.c468
-rw-r--r--arch/um/kernel/process.c98
-rw-r--r--arch/um/kernel/process_kern.c58
-rw-r--r--arch/um/kernel/ptrace.c23
-rw-r--r--arch/um/kernel/reboot.c2
-rw-r--r--arch/um/kernel/sigio_kern.c7
-rw-r--r--arch/um/kernel/sigio_user.c105
-rw-r--r--arch/um/kernel/signal_kern.c79
-rw-r--r--arch/um/kernel/skas/Makefile24
-rw-r--r--arch/um/kernel/skas/exec_user.c6
-rw-r--r--arch/um/kernel/skas/include/mode.h6
-rw-r--r--arch/um/kernel/skas/include/ptrace-skas.h10
-rw-r--r--arch/um/kernel/skas/include/skas.h4
-rw-r--r--arch/um/kernel/skas/include/uaccess.h207
-rw-r--r--arch/um/kernel/skas/mem_user.c32
-rw-r--r--arch/um/kernel/skas/mmu.c8
-rw-r--r--arch/um/kernel/skas/process.c166
-rw-r--r--arch/um/kernel/skas/process_kern.c87
-rw-r--r--arch/um/kernel/skas/sys-i386/Makefile2
-rw-r--r--arch/um/kernel/skas/sys-i386/sigcontext.c15
-rw-r--r--arch/um/kernel/skas/syscall_kern.c2
-rw-r--r--arch/um/kernel/skas/syscall_user.c4
-rw-r--r--arch/um/kernel/skas/trap_user.c6
-rw-r--r--arch/um/kernel/skas/uaccess.c219
-rw-r--r--arch/um/kernel/skas/util/Makefile7
-rw-r--r--arch/um/kernel/skas/util/mk_ptregs.c1
-rw-r--r--arch/um/kernel/smp.c104
-rw-r--r--arch/um/kernel/sys_call_table.c686
-rw-r--r--arch/um/kernel/syscall_kern.c64
-rw-r--r--arch/um/kernel/sysrq.c5
-rw-r--r--arch/um/kernel/tempfile.c7
-rw-r--r--arch/um/kernel/time.c70
-rw-r--r--arch/um/kernel/time_kern.c79
-rw-r--r--arch/um/kernel/trap_kern.c51
-rw-r--r--arch/um/kernel/trap_user.c18
-rw-r--r--arch/um/kernel/tt/Makefile6
-rw-r--r--arch/um/kernel/tt/exec_kern.c7
-rw-r--r--arch/um/kernel/tt/exec_user.c9
-rw-r--r--arch/um/kernel/tt/include/mode.h2
-rw-r--r--arch/um/kernel/tt/include/uaccess.h60
-rw-r--r--arch/um/kernel/tt/mem.c2
-rw-r--r--arch/um/kernel/tt/mem_user.c7
-rw-r--r--arch/um/kernel/tt/process_kern.c84
-rw-r--r--arch/um/kernel/tt/ptproxy/Makefile2
-rw-r--r--arch/um/kernel/tt/ptproxy/proxy.c29
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.c1
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.c12
-rw-r--r--arch/um/kernel/tt/sys-i386/Makefile2
-rw-r--r--arch/um/kernel/tt/syscall_kern.c2
-rw-r--r--arch/um/kernel/tt/syscall_user.c4
-rw-r--r--arch/um/kernel/tt/tlb.c1
-rw-r--r--arch/um/kernel/tt/tracer.c29
-rw-r--r--arch/um/kernel/tt/uaccess.c73
-rw-r--r--arch/um/kernel/tt/uaccess_user.c22
-rw-r--r--arch/um/kernel/tt/unmap.c3
-rw-r--r--arch/um/kernel/tty_log.c136
-rw-r--r--arch/um/kernel/uaccess_user.c2
-rw-r--r--arch/um/kernel/um_arch.c76
-rw-r--r--arch/um/kernel/umid.c80
-rw-r--r--arch/um/kernel/uml.lds.S (renamed from arch/um/uml.lds.S)18
-rw-r--r--arch/um/kernel/user_syms.c113
-rw-r--r--arch/um/kernel/user_util.c44
-rw-r--r--arch/um/os-Linux/Makefile6
-rw-r--r--arch/um/os-Linux/drivers/ethertap_kern.c1
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c58
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c60
-rw-r--r--arch/um/os-Linux/file.c450
-rw-r--r--arch/um/os-Linux/process.c76
-rw-r--r--arch/um/os-Linux/tty.c10
-rw-r--r--arch/um/os-Linux/user_syms.c88
-rw-r--r--arch/um/sys-i386/Makefile27
-rw-r--r--arch/um/sys-i386/bugs.c140
-rw-r--r--arch/um/sys-i386/extable.c30
-rw-r--r--arch/um/sys-i386/fault.c16
-rw-r--r--arch/um/sys-i386/ptrace_user.c8
-rw-r--r--arch/um/sys-i386/time.c24
-rw-r--r--arch/um/sys-i386/util/Makefile14
-rw-r--r--arch/um/sys-i386/util/mk_sc.c1
-rw-r--r--arch/um/sys-ia64/Makefile15
-rw-r--r--arch/um/sys-ppc/Makefile11
-rw-r--r--arch/um/util/Makefile27
-rw-r--r--arch/um/util/mk_constants_kern.c4
-rw-r--r--arch/v850/kernel/setup.c4
-rw-r--r--arch/v850/kernel/signal.c8
-rw-r--r--arch/v850/kernel/vmlinux.lds.S3
-rw-r--r--arch/x86_64/Kconfig11
-rw-r--r--arch/x86_64/Kconfig.debug12
-rw-r--r--arch/x86_64/Makefile1
-rw-r--r--arch/x86_64/defconfig109
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c3
-rw-r--r--arch/x86_64/ia32/ia32_ioctl.c15
-rw-r--r--arch/x86_64/ia32/ia32_signal.c41
-rw-r--r--arch/x86_64/ia32/ia32entry.S33
-rw-r--r--arch/x86_64/ia32/ptrace32.c6
-rw-r--r--arch/x86_64/ia32/sys_ia32.c22
-rw-r--r--arch/x86_64/kernel/Makefile1
-rw-r--r--arch/x86_64/kernel/Makefile-HEAD38
-rw-r--r--arch/x86_64/kernel/aperture.c23
-rw-r--r--arch/x86_64/kernel/cpufreq/Kconfig49
-rw-r--r--arch/x86_64/kernel/cpufreq/Makefile8
-rw-r--r--arch/x86_64/kernel/domain.c93
-rw-r--r--arch/x86_64/kernel/early_printk.c17
-rw-r--r--arch/x86_64/kernel/entry.S16
-rw-r--r--arch/x86_64/kernel/ioport.c6
-rw-r--r--arch/x86_64/kernel/mce.c117
-rw-r--r--arch/x86_64/kernel/msr.c325
-rw-r--r--arch/x86_64/kernel/pci-dma.c21
-rw-r--r--arch/x86_64/kernel/pci-gart.c290
-rw-r--r--arch/x86_64/kernel/pci-nommu.c62
-rw-r--r--arch/x86_64/kernel/process.c22
-rw-r--r--arch/x86_64/kernel/ptrace.c14
-rw-r--r--arch/x86_64/kernel/setup.c7
-rw-r--r--arch/x86_64/kernel/setup64.c26
-rw-r--r--arch/x86_64/kernel/signal.c43
-rw-r--r--arch/x86_64/kernel/smpboot.c21
-rw-r--r--arch/x86_64/kernel/time.c98
-rw-r--r--arch/x86_64/kernel/traps.c54
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S3
-rw-r--r--arch/x86_64/kernel/x8664_ksyms.c25
-rw-r--r--arch/x86_64/lib/Makefile2
-rw-r--r--arch/x86_64/lib/bitops.c140
-rw-r--r--arch/x86_64/lib/bitstr.c3
-rw-r--r--arch/x86_64/lib/memmove.c16
-rw-r--r--arch/x86_64/mm/fault.c77
-rw-r--r--arch/x86_64/mm/init.c22
-rw-r--r--arch/x86_64/mm/numa.c2
-rw-r--r--arch/x86_64/pci/Makefile4
-rw-r--r--arch/x86_64/pci/Makefile-BUS22
-rw-r--r--arch/x86_64/pci/k8-bus.c74
-rw-r--r--crypto/Kconfig15
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/tcrypt.c9
-rw-r--r--crypto/tcrypt.h104
-rw-r--r--crypto/whirlpool.c1131
-rw-r--r--drivers/atm/idt77252.c68
-rw-r--r--drivers/base/class.c9
-rw-r--r--drivers/base/node.c13
-rw-r--r--drivers/block/rd.c9
-rw-r--r--drivers/block/scsi_ioctl.c1
-rw-r--r--drivers/char/Makefile5
-rw-r--r--drivers/char/amiserial.c4
-rw-r--r--drivers/char/ip2/ip2types.h3
-rw-r--r--drivers/char/ip2main.c17
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c559
-rw-r--r--drivers/char/pty.c162
-rw-r--r--drivers/char/random.c136
-rw-r--r--drivers/char/rocket.c4
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/synclink.c556
-rw-r--r--drivers/char/synclinkmp.c558
-rw-r--r--drivers/char/tty_io.c155
-rw-r--r--drivers/char/vt.c10
-rw-r--r--drivers/char/watchdog/Kconfig6
-rw-r--r--drivers/char/watchdog/Makefile1
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c164
-rw-r--r--drivers/char/watchdog/wdt_pci.c2
-rw-r--r--drivers/cpufreq/Kconfig15
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c424
-rw-r--r--drivers/i2c/chips/asb100.c4
-rw-r--r--drivers/i2c/chips/it87.c4
-rw-r--r--drivers/i2c/chips/lm78.c4
-rw-r--r--drivers/i2c/chips/lm85.c4
-rw-r--r--drivers/i2c/chips/w83627hf.c4
-rw-r--r--drivers/i2c/chips/w83781d.c4
-rw-r--r--drivers/ide/legacy/qd65xx.h6
-rw-r--r--drivers/input/serio/gscps2.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c106
-rw-r--r--drivers/isdn/tpam/tpam_main.c47
-rw-r--r--drivers/macintosh/adbhid.c2
-rw-r--r--drivers/md/Kconfig18
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/md.c130
-rw-r--r--drivers/md/raid1.c93
-rw-r--r--drivers/md/raid10.c1780
-rw-r--r--drivers/md/raid5.c5
-rw-r--r--drivers/md/raid6main.c5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig8
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c2
-rw-r--r--drivers/media/video/meye.c2
-rw-r--r--drivers/message/fusion/mptbase.c2
-rw-r--r--drivers/misc/ibmasm/module.c12
-rw-r--r--drivers/mtd/chips/jedec_probe.c40
-rw-r--r--drivers/mtd/maps/edb7312.c8
-rw-r--r--drivers/mtd/maps/impa7.c4
-rw-r--r--drivers/mtd/nftlmount.c6
-rw-r--r--drivers/net/8139too.c66
-rw-r--r--drivers/net/Kconfig16
-rw-r--r--drivers/net/dl2k.h2
-rw-r--r--drivers/net/e1000/e1000_main.c16
-rw-r--r--drivers/net/gianfar.c4
-rw-r--r--drivers/net/hamachi.c2
-rw-r--r--drivers/net/hamradio/dmascc.c290
-rw-r--r--drivers/net/hp100.c10
-rw-r--r--drivers/net/ioc3-eth.c12
-rw-r--r--drivers/net/ixgb/ixgb_main.c132
-rw-r--r--drivers/net/rrunner.c86
-rw-r--r--drivers/net/sk98lin/skge.c10
-rw-r--r--drivers/net/smc9194.c255
-rw-r--r--drivers/net/sundance.c2
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tulip/de4x5.c16
-rw-r--r--drivers/net/tulip/dmfe.c30
-rw-r--r--drivers/net/via-rhine.c110
-rw-r--r--drivers/net/via-velocity.c72
-rw-r--r--drivers/net/via-velocity.h3
-rw-r--r--drivers/net/wan/cycx_x25.c6
-rw-r--r--drivers/parisc/lasi.c2
-rw-r--r--drivers/parisc/superio.c2
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c2
-rw-r--r--drivers/pci/hotplug/cpcihp_zt5550.c4
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c4
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c2
-rw-r--r--drivers/pci/hotplug/pciehp_core.c6
-rw-r--r--drivers/pci/hotplug/pcihp_skeleton.c2
-rw-r--r--drivers/pci/hotplug/shpchp_core.c6
-rw-r--r--drivers/pci/pci-driver.c7
-rw-r--r--drivers/pci/probe.c6
-rw-r--r--drivers/pci/remove.c20
-rw-r--r--drivers/pcmcia/au1000_generic.c15
-rw-r--r--drivers/pcmcia/cistpl.c4
-rw-r--r--drivers/pcmcia/cs.c11
-rw-r--r--drivers/pcmcia/hd64465_ss.c11
-rw-r--r--drivers/pcmcia/i82092.c20
-rw-r--r--drivers/pcmcia/i82365.c14
-rw-r--r--drivers/pcmcia/pd6729.c14
-rw-r--r--drivers/pcmcia/rsrc_mgr.c6
-rw-r--r--drivers/pcmcia/soc_common.c9
-rw-r--r--drivers/pcmcia/tcic.c12
-rw-r--r--drivers/pcmcia/yenta_socket.c9
-rw-r--r--drivers/s390/scsi/zfcp_aux.c205
-rw-r--r--drivers/s390/scsi/zfcp_def.h23
-rw-r--r--drivers/s390/scsi/zfcp_erp.c209
-rw-r--r--drivers/s390/scsi/zfcp_ext.h6
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c121
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h4
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c4
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_adapter.c43
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_driver.c4
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_port.c33
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_unit.c29
-rw-r--r--drivers/scsi/aha1542.h10
-rw-r--r--drivers/scsi/cpqfcTSinit.c51
-rw-r--r--drivers/scsi/fdomain.c51
-rw-r--r--drivers/scsi/sd.c12
-rw-r--r--drivers/scsi/sr.c12
-rw-r--r--drivers/scsi/wd7000.c47
-rw-r--r--drivers/serial/68360serial.c2
-rw-r--r--drivers/serial/sn_console.c3
-rw-r--r--drivers/tc/zs.c22
-rw-r--r--drivers/telephony/ixj.c53
-rw-r--r--drivers/telephony/ixj.h4
-rw-r--r--drivers/usb/core/config.c7
-rw-r--r--drivers/usb/core/message.c2
-rw-r--r--drivers/usb/core/urb.c4
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/gadget/inode.c4
-rw-r--r--drivers/usb/host/ehci-hub.c4
-rw-r--r--drivers/usb/host/ehci-mem.c4
-rw-r--r--drivers/usb/input/ati_remote.c4
-rw-r--r--drivers/usb/misc/auerswald.c7
-rw-r--r--drivers/usb/net/rtl8150.c2
-rw-r--r--drivers/usb/serial/usb-serial.c130
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--fs/Makefile2
-rw-r--r--fs/adfs/super.c2
-rw-r--r--fs/affs/super.c2
-rw-r--r--fs/aio.c655
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/bfs/inode.c2
-rw-r--r--fs/binfmt_aout.c2
-rw-r--r--fs/binfmt_elf.c4
-rw-r--r--fs/bio.c23
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/coda/inode.c2
-rw-r--r--fs/compat.c8
-rw-r--r--fs/efs/super.c2
-rw-r--r--fs/exec.c15
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext3/super.c2
-rw-r--r--fs/fat/file.c6
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/hostfs/Makefile26
-rw-r--r--fs/hostfs/hostfs.h79
-rw-r--r--fs/hostfs/hostfs_kern.c1024
-rw-r--r--fs/hostfs/hostfs_user.c361
-rw-r--r--fs/hpfs/super.c2
-rw-r--r--fs/hppfs/Makefile19
-rw-r--r--fs/hppfs/hppfs_kern.c815
-rw-r--r--fs/inode.c3
-rw-r--r--fs/isofs/inode.c3
-rw-r--r--fs/jffs2/super.c2
-rw-r--r--fs/jfs/super.c2
-rw-r--r--fs/libfs.c72
-rw-r--r--fs/lockd/svc.c8
-rw-r--r--fs/locks.c2
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/mpage.c3
-rw-r--r--fs/namei.c6
-rw-r--r--fs/ncpfs/file.c21
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/ncpfs/mmap.c10
-rw-r--r--fs/nfs/inode.c2
-rw-r--r--fs/nfs/nfsroot.c6
-rw-r--r--fs/nfsd/export.c5
-rw-r--r--fs/nfsd/nfsctl.c96
-rw-r--r--fs/ntfs/super.c2
-rw-r--r--fs/proc/array.c6
-rw-r--r--fs/proc/base.c76
-rw-r--r--fs/proc/inode.c2
-rw-r--r--fs/proc/proc_misc.c3
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/reiserfs/super.c2
-rw-r--r--fs/reiserfs/xattr.c11
-rw-r--r--fs/reiserfs/xattr_acl.c8
-rw-r--r--fs/romfs/inode.c2
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/ufs/super.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h2
-rw-r--r--include/asm-alpha/page.h1
-rw-r--r--include/asm-arm/arch-rpc/io.h38
-rw-r--r--include/asm-arm/hardirq.h10
-rw-r--r--include/asm-arm/memory.h4
-rw-r--r--include/asm-generic/vmlinux.lds.h7
-rw-r--r--include/asm-i386/bitops.h12
-rw-r--r--include/asm-i386/cpufeature.h13
-rw-r--r--include/asm-i386/fixmap.h19
-rw-r--r--include/asm-i386/mach-bigsmp/mach_ipi.h2
-rw-r--r--include/asm-i386/mach-es7000/mach_ipi.h2
-rw-r--r--include/asm-i386/mach-summit/mach_ipi.h2
-rw-r--r--include/asm-i386/page.h2
-rw-r--r--include/asm-i386/pgtable-2level.h7
-rw-r--r--include/asm-i386/pgtable-3level.h7
-rw-r--r--include/asm-i386/pgtable.h7
-rw-r--r--include/asm-i386/processor.h7
-rw-r--r--include/asm-ia64/dma-mapping.h3
-rw-r--r--include/asm-ia64/pgtable.h2
-rw-r--r--include/asm-ia64/processor.h20
-rw-r--r--include/asm-ppc/mpc8260.h4
-rw-r--r--include/asm-ppc/open_pic.h2
-rw-r--r--include/asm-ppc/residual.h16
-rw-r--r--include/asm-ppc/serial.h12
-rw-r--r--include/asm-ppc64/processor.h7
-rw-r--r--include/asm-ppc64/smp.h2
-rw-r--r--include/asm-ppc64/system.h1
-rw-r--r--include/asm-s390/processor.h2
-rw-r--r--include/asm-s390/timer.h2
-rw-r--r--include/asm-sparc/sigcontext.h14
-rw-r--r--include/asm-sparc64/sigcontext.h12
-rw-r--r--include/asm-um/archparam-i386.h89
-rw-r--r--include/asm-um/common.lds.S52
-rw-r--r--include/asm-um/cpufeature.h6
-rw-r--r--include/asm-um/current.h6
-rw-r--r--include/asm-um/dma-mapping.h120
-rw-r--r--include/asm-um/elf.h13
-rw-r--r--include/asm-um/fixmap.h8
-rw-r--r--include/asm-um/irq.h18
-rw-r--r--include/asm-um/local.h6
-rw-r--r--include/asm-um/mmu_context.h4
-rw-r--r--include/asm-um/module-generic.h6
-rw-r--r--include/asm-um/module-i386.h (renamed from include/asm-um/module.h)4
-rw-r--r--include/asm-um/page.h34
-rw-r--r--include/asm-um/pgtable.h109
-rw-r--r--include/asm-um/processor-generic.h43
-rw-r--r--include/asm-um/processor-i386.h4
-rw-r--r--include/asm-um/ptrace-generic.h2
-rw-r--r--include/asm-um/sections.h7
-rw-r--r--include/asm-um/smp.h2
-rw-r--r--include/asm-um/smplock.h6
-rw-r--r--include/asm-um/spinlock.h10
-rw-r--r--include/asm-um/system-generic.h9
-rw-r--r--include/asm-um/system-i386.h31
-rw-r--r--include/asm-um/thread_info.h16
-rw-r--r--include/asm-um/timex.h2
-rw-r--r--include/asm-um/uaccess.h2
-rw-r--r--include/asm-um/unistd.h5
-rw-r--r--include/asm-x86_64/acpi.h5
-rw-r--r--include/asm-x86_64/bitops.h143
-rw-r--r--include/asm-x86_64/cpufeature.h10
-rw-r--r--include/asm-x86_64/dma-mapping.h135
-rw-r--r--include/asm-x86_64/i387.h24
-rw-r--r--include/asm-x86_64/ia32.h10
-rw-r--r--include/asm-x86_64/io.h31
-rw-r--r--include/asm-x86_64/mpspec.h1
-rw-r--r--include/asm-x86_64/mtrr.h2
-rw-r--r--include/asm-x86_64/pci.h253
-rw-r--r--include/asm-x86_64/processor.h5
-rw-r--r--include/asm-x86_64/proto.h3
-rw-r--r--include/asm-x86_64/swiotlb.h36
-rw-r--r--include/asm-x86_64/system.h8
-rw-r--r--include/asm-x86_64/topology.h9
-rw-r--r--include/linux/adfs_fs_i.h2
-rw-r--r--include/linux/aio.h28
-rw-r--r--include/linux/buffer_head.h4
-rw-r--r--include/linux/cpumask.h5
-rw-r--r--include/linux/dcache.h4
-rw-r--r--include/linux/device.h1
-rw-r--r--include/linux/errno.h1
-rw-r--r--include/linux/fs.h33
-rw-r--r--include/linux/genhd.h2
-rw-r--r--include/linux/gfp.h5
-rw-r--r--include/linux/ghash.h236
-rw-r--r--include/linux/highuid.h8
-rw-r--r--include/linux/if_bridge.h2
-rw-r--r--include/linux/kobject.h5
-rw-r--r--include/linux/kref.h9
-rw-r--r--include/linux/mm.h56
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_nat_helper.h3
-rw-r--r--include/linux/node.h1
-rw-r--r--include/linux/page-flags.h10
-rw-r--r--include/linux/pci.h2
-rw-r--r--include/linux/personality.h1
-rw-r--r--include/linux/raid/md.h1
-rw-r--r--include/linux/raid/md_k.h11
-rw-r--r--include/linux/raid/raid10.h103
-rw-r--r--include/linux/rmap.h18
-rw-r--r--include/linux/rtnetlink.h4
-rw-r--r--include/linux/sched.h210
-rw-r--r--include/linux/shm.h1
-rw-r--r--include/linux/signal.h2
-rw-r--r--include/linux/slab.h1
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--include/linux/time.h2
-rw-r--r--include/linux/wait.h9
-rw-r--r--include/net/xfrm.h2
-rw-r--r--include/pcmcia/ss.h2
-rw-r--r--init/Kconfig2
-rw-r--r--init/do_mounts_rd.c20
-rw-r--r--init/main.c125
-rw-r--r--ipc/shm.c6
-rw-r--r--kernel/audit.c2
-rw-r--r--kernel/exit.c43
-rw-r--r--kernel/fork.c147
-rw-r--r--kernel/sched.c1313
-rw-r--r--kernel/signal.c31
-rw-r--r--kernel/sysctl.c41
-rw-r--r--lib/Makefile5
-rw-r--r--lib/kobject.c57
-rw-r--r--lib/kref.c29
-rw-r--r--mm/bootmem.c25
-rw-r--r--mm/filemap.c15
-rw-r--r--mm/hugetlb.c2
-rw-r--r--mm/mempolicy.c1
-rw-r--r--mm/mmap.c124
-rw-r--r--mm/page-writeback.c8
-rw-r--r--mm/page_alloc.c213
-rw-r--r--mm/readahead.c7
-rw-r--r--mm/rmap.c275
-rw-r--r--mm/slab.c69
-rw-r--r--mm/swapfile.c23
-rw-r--r--mm/vmscan.c37
-rw-r--r--net/atm/mpoa_proc.c2
-rw-r--r--net/bridge/br_input.c57
-rw-r--r--net/bridge/br_private.h2
-rw-r--r--net/core/dev.c69
-rw-r--r--net/core/rtnetlink.c85
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_icmp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_sctp.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_udp.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_core.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_helper.c8
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c2
-rw-r--r--net/ipv4/xfrm4_output.c3
-rw-r--r--net/ipv6/route.c9
-rw-r--r--net/ipv6/xfrm6_output.c2
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c2
-rw-r--r--scripts/basic/fixdep.c9
-rw-r--r--scripts/mod/sumversion.c2
-rw-r--r--security/Kconfig4
-rw-r--r--security/security.c4
-rw-r--r--security/selinux/Kconfig15
-rw-r--r--security/selinux/hooks.c103
-rw-r--r--security/selinux/selinuxfs.c266
-rw-r--r--security/selinux/ss/avtab.c12
-rw-r--r--security/selinux/ss/avtab.h2
-rw-r--r--security/selinux/ss/services.c1
-rw-r--r--sound/oss/cs46xx.c12
-rw-r--r--sound/oss/harmony.c4
-rw-r--r--sound/oss/msnd.c28
-rw-r--r--sound/oss/msnd.h9
-rw-r--r--sound/oss/msnd_pinnacle.c42
-rw-r--r--sound/oss/waveartist.c6
796 files changed, 23128 insertions, 12340 deletions
diff --git a/CREDITS b/CREDITS
index cc0cffd96d8a4..d83203ed033d2 100644
--- a/CREDITS
+++ b/CREDITS
@@ -735,6 +735,12 @@ S: Schimmelsrain 1
S: D-69231 Rauenberg
S: Germany
+N: Jean Delvare
+E: khali@linux-fr.org
+W: http://khali.linux-fr.org/
+D: Several hardware monitoring drivers
+S: France
+
N: Peter Denison
E: peterd@pnd-pc.demon.co.uk
W: http://www.pnd-pc.demon.co.uk/promise/
@@ -754,7 +760,7 @@ W: http://luxik.cdi.cz/~devik/qos/
D: HTB qdisc and random networking hacks
N: Alex deVries
-E: adevries@thepuffingroup.com
+E: alex@onefishtwo.ca
D: Various SGI parts, bits of HAL2 and Newport, PA-RISC Linux.
S: 41.5 William Street
S: Ottawa, Ontario
@@ -2838,6 +2844,9 @@ S: Markusstrasse 18
S: 8006 Zuerich
S: Switzerland
+N: Manuel Estrada Sainz
+D: Firmware loader (request_firmware)
+
N: Wayne Salamon
E: wsalamon@tislabs.com
E: wsalamon@nai.com
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 7b256c12a5f54..f25b3953f5139 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -356,10 +356,10 @@ Generally, inline functions are preferable to macros resembling functions.
Macros with multiple statements should be enclosed in a do - while block:
-#define macrofun(a,b,c) \
+#define macrofun(a, b, c) \
do { \
if (a == 5) \
- do_this(b,c); \
+ do_this(b, c); \
} while (0)
Things to avoid when using macros:
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
index 1df474c4ecdb4..b90d798464507 100644
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -227,6 +227,9 @@ TEA/XTEA algorithm contributors:
Khazad algorithm contributors:
Aaron Grothe
+Whirlpool algorithm contributors:
+ Aaron Grothe
+
Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
Please send any credits updates or corrections to:
diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt
index 70685dde39c40..dd62c7b80b3f8 100644
--- a/Documentation/driver-model/bus.txt
+++ b/Documentation/driver-model/bus.txt
@@ -5,20 +5,21 @@ Definition
~~~~~~~~~~
struct bus_type {
- char * name;
- rwlock_t lock;
- atomic_t refcount;
+ char * name;
- struct list_head node;
- struct list_head devices;
- struct list_head drivers;
+ struct subsystem subsys;
+ struct kset drivers;
+ struct kset devices;
- struct driver_dir_entry dir;
- struct driver_dir_entry device_dir;
- struct driver_dir_entry driver_dir;
+ struct bus_attribute * bus_attrs;
+ struct device_attribute * dev_attrs;
+ struct driver_attribute * drv_attrs;
- int (*match) (struct device * dev, struct device_driver * drv);
- struct device (*add) (struct device * parent, char * bus_id);
+ int (*match)(struct device * dev, struct device_driver * drv);
+ int (*hotplug) (struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size);
+ int (*suspend)(struct device * dev, u32 state);
+ int (*resume)(struct device * dev);
};
int bus_register(struct bus_type * bus);
@@ -47,7 +48,7 @@ Registration
When a bus driver is initialized, it calls bus_register. This
initializes the rest of the fields in the bus object and inserts it
into a global list of bus types. Once the bus object is registered,
-the fields in it (e.g. the rwlock_t) are usable by the bus driver.
+the fields in it are usable by the bus driver.
Callbacks
@@ -71,40 +72,6 @@ When a driver is registered with the bus, the bus's list of devices is
iterated over, and the match callback is called for each device that
does not have a driver associated with it.
-add(): Adding a child device
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The add callback is available to notify the bus about a child device
-at a particular location.
-
-The parent parameter is the parent device of the child to be added. If
-parent == NULL, the bus should add the device as a child of a default
-parent device or as a child of the root. This policy decision is up to
-the bus driver.
-
-The format of the bus_id field should be consistent with the format of
-the bus_id field of the rest of the devices on the bus. This requires
-the caller to know the format.
-
-On return, the bus driver should return a pointer to the device that
-was created. If the device was not created, the bus driver should
-return an appropriate error code. Refer to include/linux/err.h for
-helper functions to encode errors. Some sample code:
-
-struct device * pci_bus_add(struct device * parent, char * bus_id)
-{
- ...
- /* the device already exists */
- return ERR_PTR(-EEXIST);
- ...
-}
-
-The caller can check the return value using IS_ERR():
-
- struct device * newdev = pci_bus_type.add(parent,bus_id);
- if (IS_ERR(newdev)) {
- ...
- }
Device and Driver Lists
@@ -118,10 +85,11 @@ necessary.
The LDM core provides helper functions for iterating over each list.
-int bus_for_each_dev(struct bus_type * bus, void * data,
- int (*callback)(struct device * dev, void * data));
-int bus_for_each_drv(struct bus_type * bus, void * data,
- int (*callback)(struct device_driver * drv, void * data));
+int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
+ int (*fn)(struct device *, void *));
+
+int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+ void * data, int (*fn)(struct device_driver *, void *));
These helpers iterate over the respective list, and call the callback
for each device or driver in the list. All list accesses are
@@ -168,9 +136,9 @@ hierarchy:
Exporting Attributes
~~~~~~~~~~~~~~~~~~~~
struct bus_attribute {
- struct attribute attr;
- ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off);
- ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off);
+ struct attribute attr;
+ ssize_t (*show)(struct bus_type *, char * buf);
+ ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};
Bus drivers can export attributes using the BUS_ATTR macro that works
diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index 02968c532a4fc..23a4d98f99b87 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -17,6 +17,33 @@ Defaults are marked with (*).
bsddf (*) Makes `df' act like BSD.
minixdf Makes `df' act like Minix.
+barrier=1 This enables/disables barriers. barrier=0 disables it,
+ barrier=1 enables it.
+
+orlov (*) This enables the new Orlov block allocator. It's
+ enabled by default.
+
+oldalloc This disables the Orlov block allocator and
+ enables the old block allocator. Orlov should
+ have better performance, we'd like to get some
+ feedback if it's the contrary for you.
+
+user_xattr (*) Enables POSIX Extended Attributes. It's enabled by
+ default, however you need to confifure its support
+ (CONFIG_EXT2_FS_XATTR). This is neccesary if you want
+ to use POSIX Acces Control Lists support. You can visit
+ http://acl.bestbits.at to know more about POSIX Extended
+ attributes.
+
+nouser_xattr Disables POSIX Extended Attributes.
+
+acl (*) Enables POSIX Access Control Lists support. This is
+ enabled by default, however you need to configure
+ its support (CONFIG_EXT2_FS_POSIX_ACL). If you want
+ to know more about ACLs visit http://acl.bestbits.at
+
+noacl This option disables POSIX Access Control List support.
+
check=none, nocheck (*) Don't do extra checking of bitmaps on mount
(check=normal and check=strict options removed)
@@ -336,9 +363,8 @@ and are copied into the filesystem. If a transaction is incomplete at
the time of the crash, then there is no guarantee of consistency for
the blocks in that transaction so they are discarded (which means any
filesystem changes they represent are also lost).
-
-The ext3 code is currently (Apr 2001) available for 2.2 kernels only,
-and not yet available for 2.4 kernels.
+Check Documentation/filesystems/ext3.txt if you want to read more about
+ext3 and journaling.
References
==========
@@ -349,8 +375,6 @@ Design & Implementation http://e2fsprogs.sourceforge.net/ext2intro.html
Journaling (ext3) ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/
Hashed Directories http://kernelnewbies.org/~phillips/htree/
Filesystem Resizing http://ext2resize.sourceforge.net/
-Extended Attributes &
-Access Control Lists http://acl.bestbits.at/
Compression (*) http://www.netspace.net.au/~reiter/e2compr/
Implementations for:
diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt
index ff220afb1225c..9ab7f446f7adb 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -22,6 +22,63 @@ journal=inum When a journal already exists, this option is
the inode which will represent the ext3 file
system's journal file.
+noload Don't load the journal on mounting.
+
+data=journal All data are committed into the journal prior
+ to being written into the main file system.
+
+data=ordered (*) All data are forced directly out to the main file
+ system prior to its metadata being committed to
+ the journal.
+
+data=writeback Data ordering is not preserved, data may be
+ written into the main file system after its
+ metadata has been committed to the journal.
+
+commit=nrsec (*) Ext3 can be told to sync all its data and metadata
+ every 'nrsec' seconds. The default value is 5 seconds.
+ This means that if you lose your power, you will lose,
+ as much, the latest 5 seconds of work (your filesystem
+ will not be damaged though, thanks to journaling). This
+ default value (or any low value) will hurt performance,
+ but it's good for data-safety. Setting it to 0 will
+ have the same effect than leaving the default 5 sec.
+ Setting it to very large values will improve
+ performance.
+
+barrier=1 This enables/disables barriers. barrier=0 disables it,
+ barrier=1 enables it.
+
+orlov (*) This enables the new Orlov block allocator. It's enabled
+ by default.
+
+oldalloc This disables the Orlov block allocator and enables the
+ old block allocator. Orlov should have better performance,
+ we'd like to get some feedback if it's the contrary for
+ you.
+
+user_xattr (*) Enables POSIX Extended Attributes. It's enabled by
+ default, however you need to confifure its support
+ (CONFIG_EXT3_FS_XATTR). This is neccesary if you want
+ to use POSIX Acces Control Lists support. You can visit
+ http://acl.bestbits.at to know more about POSIX Extended
+ attributes.
+
+nouser_xattr Disables POSIX Extended Attributes.
+
+acl (*) Enables POSIX Access Control Lists support. This is
+ enabled by default, however you need to configure
+ its support (CONFIG_EXT3_FS_POSIX_ACL). If you want
+ to know more about ACLs visit http://acl.bestbits.at
+
+noacl This option disables POSIX Access Control List support.
+
+reservation
+
+noreservation
+
+resize=
+
bsddf (*) Make 'df' act like BSD.
minixdf Make 'df' act like Minix.
@@ -30,8 +87,6 @@ nocheck
debug Extra debugging information is sent to syslog.
-noload Don't load the journal on mounting.
-
errors=remount-ro(*) Remount the filesystem read-only on an error.
errors=continue Keep going on a filesystem error.
errors=panic Panic and halt the machine if an error occurs.
@@ -48,17 +103,6 @@ resuid=n The user ID which may use the reserved blocks.
sb=n Use alternate superblock at this location.
-data=journal All data are committed into the journal prior
- to being written into the main file system.
-
-data=ordered (*) All data are forced directly out to the main file
- system prior to its metadata being committed to
- the journal.
-
-data=writeback Data ordering is not preserved, data may be
- written into the main file system after its
- metadata has been committed to the journal.
-
quota Quota options are currently silently ignored.
noquota (see fs/ext3/super.c, line 594)
grpquota
@@ -114,7 +158,7 @@ Compatibility
-------------
Ext2 partitions can be easily convert to ext3, with `tune2fs -j <dev>`.
- Ext3 is fully compatible with Ext2. Ext3 partitions can easily be
+Ext3 is fully compatible with Ext2. Ext3 partitions can easily be
mounted as Ext2.
External Tools
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 186f38c13af11..8d6601c9d3e42 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -169,16 +169,18 @@ information. The statm file contains more detailed information about the
process memory usage. Its seven fields are explained in Table 1-2.
-Table 1-2: Contents of the statm files
+Table 1-2: Contents of the statm files (as of 2.6.8-rc3)
..............................................................................
- File Content
- size total program size
- resident size of memory portions
- shared number of pages that are shared
- trs number of pages that are 'code'
- drs number of pages of data/stack
- lrs number of pages of library
- dt number of dirty pages
+ Field Content
+ size total program size (pages) (same as VmSize in status)
+ resident size of memory portions (pages) (same as VmRSS in status)
+ shared number of pages that are shared (i.e. backed by a file)
+ trs number of pages that are 'code' (not including libs; broken,
+ includes data segment)
+ lrs number of pages of library (always 0 on 2.6)
+ drs number of pages of data/stack (including libs; broken,
+ includes library text)
+ dt number of dirty pages (always 0 on 2.6)
..............................................................................
1.2 Kernel data
@@ -1174,6 +1176,12 @@ for writeout by the pdflush daemons. It is expressed in 100'ths of a second.
Data which has been dirty in-memory for longer than this interval will be
written out next time a pdflush daemon wakes up.
+legacy_va_layout
+----------------
+
+If non-zero, this sysctl disables the new 32-bit mmap mmap layout - the kernel
+will use the legacy (2.4) layout for all processes.
+
lower_zone_protection
---------------------
diff --git a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface
index f651de4873f8b..3e74daeb901d1 100644
--- a/Documentation/i2c/sysfs-interface
+++ b/Documentation/i2c/sysfs-interface
@@ -104,7 +104,7 @@ in[0-8]_input Voltage input value.
in7_* varies
in8_* varies
-in0_ref CPU core reference voltage.
+cpu[0-1]_vid CPU core reference voltage.
Unit: millivolt
Read only.
Not always correct.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 3066ab3c0271e..c0d8bee481461 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -579,6 +579,20 @@ running once the system is up.
so, the driver will manage that printer.
See also header of drivers/char/lp.c.
+ lpj=n [KNL]
+ Sets loops_per_jiffy to given constant, thus avoiding
+ time-consuming boot-time autodetection (up to 250 ms per
+ CPU). 0 enables autodetection (default). To determine
+ the correct value for your kernel, boot with normal
+ autodetection and see what value is printed. Note that
+ on SMP systems the preset will be applied to all CPUs,
+ which is likely to cause problems if your CPUs need
+ significantly divergent settings. An incorrect value
+ will cause delays in the kernel to be wrong, leading to
+ unpredictable I/O errors and other breakage. Although
+ unlikely, in the extreme case this might damage your
+ hardware.
+
ltpc= [NET]
Format: <io>,<irq>,<dma>
@@ -752,6 +766,8 @@ running once the system is up.
nomce [IA-32] Machine Check Exception
+ noresidual [PPC] Don't use residual data on PReP machines.
+
noresume [SWSUSP] Disables resume and restore original swap space.
no-scroll [VGA] Disables scrollback.
diff --git a/Documentation/laptop-mode.txt b/Documentation/laptop-mode.txt
index 065e59cbb3b3c..dc4e810afdcd0 100644
--- a/Documentation/laptop-mode.txt
+++ b/Documentation/laptop-mode.txt
@@ -249,7 +249,7 @@ MINIMUM_BATTERY_MINUTES=10
# playing.
#READAHEAD=4096
-# Shall we remount journaled fs. with appropiate commit interval? (1=yes)
+# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
#DO_REMOUNTS=1
# And shall we add the "noatime" option to that as well? (1=yes)
diff --git a/Documentation/sched-domains.txt b/Documentation/sched-domains.txt
index b5da811fcbcb7..a9e990ab980fa 100644
--- a/Documentation/sched-domains.txt
+++ b/Documentation/sched-domains.txt
@@ -5,12 +5,13 @@ MUST be NULL terminated, and domain structures should be per-CPU as they
are locklessly updated.
Each scheduling domain spans a number of CPUs (stored in the ->span field).
-A domain's span MUST be a superset of it child's span, and a base domain
-for CPU i MUST span at least i. The top domain for each CPU will generally
-span all CPUs in the system although strictly it doesn't have to, but this
-could lead to a case where some CPUs will never be given tasks to run unless
-the CPUs allowed mask is explicitly set. A sched domain's span means "balance
-process load among these CPUs".
+A domain's span MUST be a superset of it child's span (this restriction could
+be relaxed if the need arises), and a base domain for CPU i MUST span at least
+i. The top domain for each CPU will generally span all CPUs in the system
+although strictly it doesn't have to, but this could lead to a case where some
+CPUs will never be given tasks to run unless the CPUs allowed mask is
+explicitly set. A sched domain's span means "balance process load among these
+CPUs".
Each scheduling domain must have one or more CPU groups (struct sched_group)
which are organised as a circular one way linked list from the ->groups
@@ -46,6 +47,20 @@ The implementor should read comments in include/linux/sched.h:
struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
the specifics and what to tune.
+For SMT, the architecture must define CONFIG_SCHED_SMT and provide a
+cpumask_t cpu_sibling_map[NR_CPUS], where cpu_sibling_map[i] is the mask of
+all "i"'s siblings as well as "i" itself.
+
+Architectures may retain the regular override the default SD_*_INIT flags
+while using the generic domain builder in kernel/sched.c if they wish to
+retain the traditional SMT->SMP->NUMA topology (or some subset of that). This
+can be done by #define'ing ARCH_HASH_SCHED_TUNE.
+
+Alternatively, the architecture may completely override the generic domain
+builder by #define'ing ARCH_HASH_SCHED_DOMAIN, and exporting your
+arch_init_sched_domains function. This function will attach domains to all
+CPUs using cpu_attach_domain.
+
Implementors should change the line
#undef SCHED_DOMAIN_DEBUG
to
diff --git a/Documentation/sched-stats.txt b/Documentation/sched-stats.txt
new file mode 100644
index 0000000000000..6f72021aae51f
--- /dev/null
+++ b/Documentation/sched-stats.txt
@@ -0,0 +1,153 @@
+Version 10 of schedstats includes support for sched_domains, which
+hit the mainline kernel in 2.6.7. Some counters make more sense to be
+per-runqueue; other to be per-domain. Note that domains (and their associated
+information) will only be pertinent and available on machines utilizing
+CONFIG_SMP.
+
+In version 10 of schedstat, there is at least one level of domain
+statistics for each cpu listed, and there may well be more than one
+domain. Domains have no particular names in this implementation, but
+the highest numbered one typically arbitrates balancing across all the
+cpus on the machine, while domain0 is the most tightly focused domain,
+sometimes balancing only between pairs of cpus. At this time, there
+are no architectures which need more than three domain levels. The first
+field in the domain stats is a bit map indicating which cpus are affected
+by that domain.
+
+These fields are counters, and only increment. Programs which make use
+of these will need to start with a baseline observation and then calculate
+the change in the counters at each subsequent observation. A perl script
+which does this for many of the fields is available at
+
+ http://eaglet.rain.com/rick/linux/schedstat/
+
+Note that any such script will necessarily be version-specific, as the main
+reason to change versions is changes in the output format. For those wishing
+to write their own scripts, the fields are described here.
+
+CPU statistics
+--------------
+cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
+
+NOTE: In the sched_yield() statistics, the active queue is considered empty
+ if it has only one process in it, since obviously the process calling
+ sched_yield() is that process.
+
+First four fields are sched_yield() statistics:
+ 1) # of times both the active and the expired queue were empty
+ 2) # of times just the active queue was empty
+ 3) # of times just the expired queue was empty
+ 4) # of times sched_yield() was called
+
+Next four are schedule() statistics:
+ 5) # of times the active queue had at least one other process on it
+ 6) # of times we switched to the expired queue and reused it
+ 7) # of times schedule() was called
+ 8) # of times schedule() left the processor idle
+
+Next four are active_load_balance() statistics:
+ 9) # of times active_load_balance() was called
+ 10) # of times active_load_balance() caused this cpu to gain a task
+ 11) # of times active_load_balance() caused this cpu to lose a task
+ 12) # of times active_load_balance() tried to move a task and failed
+
+Next three are try_to_wake_up() statistics:
+ 13) # of times try_to_wake_up() was called
+ 14) # of times try_to_wake_up() successfully moved the awakening task
+ 15) # of times try_to_wake_up() attempted to move the awakening task
+
+Next two are wake_up_new_task() statistics:
+ 16) # of times wake_up_new_task() was called
+ 17) # of times wake_up_new_task() successfully moved the new task
+
+Next one is a sched_migrate_task() statistic:
+ 18) # of times sched_migrate_task() was called
+
+Next one is a sched_balance_exec() statistic:
+ 19) # of times sched_balance_exec() was called
+
+Next three are statistics describing scheduling latency:
+ 20) sum of all time spent running by tasks on this processor (in ms)
+ 21) sum of all time spent waiting to run by tasks on this processor (in ms)
+ 22) # of tasks (not necessarily unique) given to the processor
+
+The last six are statistics dealing with pull_task():
+ 23) # of times pull_task() moved a task to this cpu when newly idle
+ 24) # of times pull_task() stole a task from this cpu when another cpu
+ was newly idle
+ 25) # of times pull_task() moved a task to this cpu when idle
+ 26) # of times pull_task() stole a task from this cpu when another cpu
+ was idle
+ 27) # of times pull_task() moved a task to this cpu when busy
+ 28) # of times pull_task() stole a task from this cpu when another cpu
+ was busy
+
+
+Domain statistics
+-----------------
+One of these is produced per domain for each cpu described. (Note that if
+CONFIG_SMP is not defined, *no* domains are utilized and these lines
+will not appear in the output.)
+
+domain<N> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+
+The first field is a bit mask indicating what cpus this domain operates over.
+
+The next fifteen are a variety of load_balance() statistics:
+
+ 1) # of times in this domain load_balance() was called when the cpu
+ was idle
+ 2) # of times in this domain load_balance() was called when the cpu
+ was busy
+ 3) # of times in this domain load_balance() was called when the cpu
+ was just becoming idle
+ 4) # of times in this domain load_balance() tried to move one or more
+ tasks and failed, when the cpu was idle
+ 5) # of times in this domain load_balance() tried to move one or more
+ tasks and failed, when the cpu was busy
+ 6) # of times in this domain load_balance() tried to move one or more
+ tasks and failed, when the cpu was just becoming idle
+ 7) sum of imbalances discovered (if any) with each call to
+ load_balance() in this domain when the cpu was idle
+ 8) sum of imbalances discovered (if any) with each call to
+ load_balance() in this domain when the cpu was busy
+ 9) sum of imbalances discovered (if any) with each call to
+ load_balance() in this domain when the cpu was just becoming idle
+ 10) # of times in this domain load_balance() was called but did not find
+ a busier queue while the cpu was idle
+ 11) # of times in this domain load_balance() was called but did not find
+ a busier queue while the cpu was busy
+ 12) # of times in this domain load_balance() was called but did not find
+ a busier queue while the cpu was just becoming idle
+ 13) # of times in this domain a busier queue was found while the cpu was
+ idle but no busier group was found
+ 14) # of times in this domain a busier queue was found while the cpu was
+ busy but no busier group was found
+ 15) # of times in this domain a busier queue was found while the cpu was
+ just becoming idle but no busier group was found
+
+Next two are sched_balance_exec() statistics:
+ 17) # of times in this domain sched_balance_exec() successfully pushed
+ a task to a new cpu
+ 18) # of times in this domain sched_balance_exec() tried but failed to
+ push a task to a new cpu
+
+Next two are try_to_wake_up() statistics:
+ 19) # of times in this domain try_to_wake_up() tried to move a task based
+ on affinity and cache warmth
+ 20) # of times in this domain try_to_wake_up() tried to move a task based
+ on load balancing
+
+
+/proc/<pid>/schedstat
+----------------
+schedstats also adds a new /proc/<pid/schedstat file to include some of
+the same information on a per-process level. There are three fields in
+this file correlating to fields 20, 21, and 22 in the CPU fields, but
+they only apply for that process.
+
+A program could be easily written to make use of these extra fields to
+report on how well a particular process or set of processes is faring
+under the scheduler's policies. A simple version of such a program is
+available at
+ http://eaglet.rain.com/rick/linux/schedstat/v10/latency.c
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 9a193fc865383..5ba1df29ab91f 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -23,7 +23,6 @@ show up in /proc/sys/kernel:
- dentry-state
- domainname
- hostname
-- htab-reclaim [ PPC only ]
- hotplug
- java-appletviewer [ binfmt_java, obsolete ]
- java-interpreter [ binfmt_java, obsolete ]
@@ -54,7 +53,6 @@ show up in /proc/sys/kernel:
- tainted
- threads-max
- version
-- zero-paged [ PPC only ]
==============================================================
@@ -145,14 +143,6 @@ see the hostname(1) man page.
==============================================================
-htab-reclaim: (PPC only)
-
-Setting this to a non-zero value, the PowerPC htab
-(see Documentation/powerpc/ppc_htab.txt) is pruned
-each time the system hits the idle loop.
-
-==============================================================
-
hotplug:
Path for the hotplug policy agent.
@@ -322,11 +312,3 @@ can be ORed together:
Set by modutils >= 2.4.9 and module-init-tools.
4 - Unsafe SMP processors: SMP with CPUs not designed for SMP.
-==============================================================
-
-zero-paged: (PPC only)
-
-When enabled (non-zero), Linux-PPC will pre-zero pages in
-the idle loop, possibly speeding up get_free_pages. Since
-this only affects what the idle loop is doing, you should
-enable this and see if anything changes.
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index d78f8dbf9e8be..7f8570a7bdbab 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -136,17 +136,25 @@ PCI
IOMMU
- iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,soft]
+ iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge]
+ [,forcesac][,fullflush][,nomerge][,noaperture]
size set size of iommu (in bytes)
noagp don't initialize the AGP driver and use full aperture.
off don't use the IOMMU
leak turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
memaper[=order] allocate an own aperture over RAM with size 32MB^order.
noforce don't force IOMMU usage. Default.
- force Force IOMMU
- soft Use software bounce buffering for non 32bit IO. Default on Intel
- machines.
-
- swiotlb=pages
-
- Prereserve that many 4K pages for the software IO bounce buffering.
+ force Force IOMMU.
+ merge Do SG merging. Implies force (experimental)
+ nomerge Don't do SG merging.
+ forcesac For SAC mode for masks <40bits (experimental)
+ fullflush Flush IOMMU on each allocation (default)
+ nofullflush Don't use IOMMU fullflush
+ allowed overwrite iommu off workarounds for specific chipsets.
+ soft Use software bounce buffering (default for Intel machines)
+ noaperture Don't touch the aperture for AGP.
+
+ swiotlb=pages[,force]
+
+ pages Prereserve that many 128K pages for the software IO bounce buffering.
+ force Force all IO through the software TLB.
diff --git a/MAINTAINERS b/MAINTAINERS
index 64ab46b1ae48c..c0aa89538998c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -169,7 +169,7 @@ ACI MIXER DRIVER
P: Robert Siemer
M: Robert.Siemer@gmx.de
L: linux-sound@vger.kernel.org
-W: http://www.uni-karlsruhe.de/~Robert.Siemer/Private/
+W: http://www.stud.uni-karlsruhe.de/~uh1b/
S: Maintained
ACP/MWAVE MODEM
@@ -195,8 +195,14 @@ S: Maintained
AD1816 SOUND DRIVER
P: Thorsten Knabe
-W: http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
-W: http://www.tu-darmstadt.de/~tek01/projects/linux.html
+M: Thorsten Knabe <linux@thorsten-knabe.de>
+W: http://linux.thorsten-knabe.de
+S: Maintained
+
+ADM1025 HARDWARE MONITOR DRIVER
+P: Jean Delvare
+M: khali@linux-fr.org
+L: sensors@stimpy.netroedge.com
S: Maintained
ADT746X FAN DRIVER
@@ -762,8 +768,8 @@ M: saw@saw.sw.com.sg
S: Maintained
EMU10K1 SOUND DRIVER
-P: Rui Sousa
-M: rui.p.m.sousa@clix.pt
+P: James Courtier-Dutton
+M: James@superbug.demon.co.uk
L: emu10k1-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/emu10k1/
S: Maintained
@@ -827,10 +833,8 @@ M: viro@math.psu.edu
S: Maintained
FIRMWARE LOADER (request_firmware)
-P: Manuel Estrada Sainz
-M: ranty@debian.org
L: linux-kernel@vger.kernel.org
-S: Maintained
+S: Orphan
FPU EMULATOR
P: Bill Metzenthen
@@ -1329,6 +1333,18 @@ L: linux-security-module@wirex.com
W: http://lsm.immunix.org
S: Supported
+LM83 HARDWARE MONITOR DRIVER
+P: Jean Delvare
+M: khali@linux-fr.org
+L: sensors@stimpy.netroedge.com
+S: Maintained
+
+LM90 HARDWARE MONITOR DRIVER
+P: Jean Delvare
+M: khali@linux-fr.org
+L: sensors@stimpy.netroedge.com
+S: Maintained
+
LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
P: Richard Russon (FlatCap)
M: ldm@flatcap.org
@@ -1908,6 +1924,12 @@ M: thomas@winischhofer.net
W: http://www.winischhofer.net/linuxsisvga.shtml
S: Maintained
+SMSC47M1 HARDWARE MONITOR DRIVER
+P: Jean Delvare
+M: khali@linux-fr.org
+L: sensors@stimpy.netroedge.com
+S: Odd Fixes
+
SMB FILESYSTEM
P: Urban Widmark
M: urban@teststation.com
@@ -2412,6 +2434,12 @@ M: johnpol@2ka.mipt.ru
L: sensors@stimpy.netroedge.com
S: Maintained
+W83L785TS HARDWARE MONITOR DRIVER
+P: Jean Delvare
+M: khali@linux-fr.org
+L: sensors@stimpy.netroedge.com
+S: Odd Fixes
+
WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
P: Nenad Corbic
M: ncorbic@sangoma.com
diff --git a/Makefile b/Makefile
index 9366f1eb39a21..962eda0a501ff 100644
--- a/Makefile
+++ b/Makefile
@@ -279,8 +279,8 @@ cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
# cc-version
# Usage gcc-ver := $(call cc-version $(CC))
-cc-version = $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh \
- $(if $(1), $(1), $(CC))
+cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh \
+ $(if $(1), $(1), $(CC)))
# Look for make include files relative to root of kernel src
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 6fd8546554e9b..4933f3ce58339 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -246,8 +246,7 @@ alpha_clone(unsigned long clone_flags, unsigned long usp,
if (!usp)
usp = rdusp();
- return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0,
- parent_tid, child_tid);
+ return do_fork(clone_flags, usp, regs, 0, parent_tid, child_tid);
}
int
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index dd1d9195c6c5c..881bb26aba619 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -469,9 +469,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void
@@ -533,9 +531,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
@@ -608,21 +604,20 @@ do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
siginfo_t info;
int signr;
unsigned long single_stepping = ptrace_cancel_bpt(current);
+ struct k_sigaction ka;
if (!oldset)
oldset = &current->blocked;
/* This lets the debugger run, ... */
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
/* ... so re-check the single stepping. */
single_stepping |= ptrace_cancel_bpt(current);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- struct k_sigaction *ka = &current->sighand->action[signr-1];
-
- if (r0) syscall_restart(r0, r19, regs, ka);
- handle_signal(signr, ka, &info, oldset, regs, sw);
+ if (r0) syscall_restart(r0, r19, regs, &ka);
+ handle_signal(signr, &ka, &info, oldset, regs, sw);
if (single_stepping)
ptrace_set_bpt(current); /* re-set bpt */
return 1;
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 3a4c9d6e214ec..6614f9f199224 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -411,15 +411,6 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
return 0;
}
-static struct task_struct * __init
-fork_by_hand(void)
-{
- /* Don't care about the contents of regs since we'll never
- reschedule the forked task. */
- struct pt_regs regs;
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
/*
* Bring one cpu online.
*/
@@ -435,15 +426,10 @@ smp_boot_one_cpu(int cpuid)
the other task-y sort of data structures set up like we
wish. We can't use kernel_thread since we must avoid
rescheduling the child. */
- idle = fork_by_hand();
+ idle = fork_idle(cpuid);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpuid);
- wake_up_forked_process(idle);
-
- init_idle(idle, cpuid);
- unhash_process(idle);
-
DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
cpuid, idle->state, idle->flags));
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 711124368640b..5d590db4e23bc 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -366,7 +366,7 @@ time_init(void)
BCD_TO_BIN(year);
}
- /* PC-like is standard; used for year < 20 || year >= 70 */
+ /* PC-like is standard; used for year >= 70 */
epoch = 1900;
if (year < 20)
epoch = 2000;
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index d159b8f0d022b..d867e81302c24 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -46,11 +46,6 @@ SECTIONS
__setup_end = .;
. = ALIGN(8);
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
-
- . = ALIGN(8);
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index 31a3f63433f37..a839578e9f56e 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -313,7 +313,7 @@ void __init paging_init(void)
zones_size[ZONE_DMA] = dma_local_pfn;
zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn;
}
- free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size, start_pfn, NULL);
+ free_area_init_node(nid, NODE_DATA(nid), zones_size, start_pfn, NULL);
}
/* Initialize the kernel's ZERO_PGE. */
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9686e04d4c4e2..4be8ac939fe11 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -402,7 +402,7 @@ config FPE_NWFPE
config FPE_NWFPE_XP
bool "Support extended precision"
- depends on FPE_NWFPE
+ depends on FPE_NWFPE && !CPU_BIG_ENDIAN
help
Say Y to include 80-bit support in the kernel floating-point
emulator. Otherwise, only 32 and 64-bit support is compiled in.
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index c3a87663b040b..5797b1b100a1b 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -121,9 +121,9 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
DO_STATS ( device_info->total_allocs++ );
buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
- if (buf == 0) {
+ if (buf == NULL) {
dev_warn(dev, "%s: kmalloc failed\n", __func__);
- return 0;
+ return NULL;
}
if (size <= device_info->small_buffer_size) {
@@ -137,16 +137,16 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
DO_STATS ( device_info->lbp_allocs++ );
} else {
- pool = 0;
+ pool = NULL;
safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC);
}
- if (safe == 0) {
+ if (safe == NULL) {
dev_warn(device_info->dev,
"%s: could not alloc dma memory (size=%d)\n",
__func__, size);
kfree(buf);
- return 0;
+ return NULL;
}
#ifdef STATS
@@ -216,27 +216,33 @@ static inline dma_addr_t
map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction dir)
{
- dma_addr_t dma_addr;
struct dmabounce_device_info *device_info = find_dmabounce_dev(dev);
+ dma_addr_t dma_addr;
+ int needs_bounce = 0;
if (device_info)
DO_STATS ( device_info->map_op_count++ );
+ dma_addr = virt_to_dma(dev, ptr);
+
if (dev->dma_mask) {
+ unsigned long mask = *dev->dma_mask;
unsigned long limit;
- limit = (*dev->dma_mask + 1) & ~(*dev->dma_mask);
- if (limit && (size > limit)) {
- dev_err(dev, "DMA mapping too big "
- "(requested %#x mask %#Lx)\n",
- size, *dev->dma_mask);
+ limit = (mask + 1) & ~mask;
+ if (limit && size > limit) {
+ dev_err(dev, "DMA mapping too big (requested %#x "
+ "mask %#Lx)\n", size, *dev->dma_mask);
return ~0;
}
- }
- dma_addr = virt_to_dma(dev, ptr);
+ /*
+ * Figure out if we need to bounce from the DMA mask.
+ */
+ needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask;
+ }
- if (device_info && dma_needs_bounce(dev, dma_addr, size)) {
+ if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) {
struct safe_buffer *buf;
buf = alloc_safe_buffer(device_info, ptr, size, dir);
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 18ba42e694e43..16f30a3551ad7 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -761,9 +761,6 @@ static void __sa1111_remove(struct sa1111 *sachip)
*/
int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
- unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr);
- u32 dma_mask = *dev->dma_mask;
-
/*
* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the
@@ -771,14 +768,8 @@ int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
* SDRAM bank 1 on Neponset). The default configuration selects
* Assabet, so any address in bank 1 is necessarily invalid.
*/
- if ((machine_is_assabet() || machine_is_pfs168()) &&
- (addr >= 0xc8000000 || (addr + size) >= 0xc8000000))
- return 1;
-
- /*
- * Check to see if either the start or end are illegal.
- */
- return ((addr & ~dma_mask)) || ((addr + size - 1) & ~dma_mask);
+ return ((machine_is_assabet() || machine_is_pfs168()) &&
+ (addr >= 0xc8000000 || (addr + size) >= 0xc8000000));
}
struct sa1111_save_data {
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 43f0c66943bbb..b05ed835ba498 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -105,6 +105,7 @@ EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memscan);
+EXPORT_SYMBOL_NOVERS(memchr);
EXPORT_SYMBOL_NOVERS(__memzero);
/* user mem (segment) */
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 69a61186a18ad..b9bd4158bf0c6 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -639,9 +639,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
return;
}
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, tsk);
+ force_sigsegv(sig, tsk);
}
/*
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index fb26b3bf96b1c..7cbd18e95bb01 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -217,11 +217,8 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third,
return ret;
return put_user(raddr, (ulong __user *)third);
}
- case 1: /* iBCS2 emulator entry point */
- if (!segment_eq(get_fs(), get_ds()))
- return -EINVAL;
- return do_shmat(first, (char __user *) ptr,
- second, (ulong __user *) third);
+ case 1: /* Of course, we don't support iBCS2! */
+ return -EINVAL;
}
case SHMDT:
return sys_shmdt ((char __user *)ptr);
@@ -257,7 +254,7 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct
if (!newsp)
newsp = regs->ARM_sp;
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL);
+ return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
}
asmlinkage int sys_vfork(struct pt_regs *regs)
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index a5db0ddca6a42..355c8959d590f 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -38,9 +38,6 @@ SECTIONS
__early_begin = .;
*(__early_param)
__early_end = .;
- __start___param = .;
- *(__param)
- __stop___param = .;
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 169c28b5f6b20..a12ade71b25aa 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/gpio.c
+/* linux/arch/arm/mach-s3c2410/clock.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -99,7 +99,9 @@ void clk_put(struct clk *clk)
int clk_enable(struct clk *clk)
{
- s3c2410_clk_enable(clk->ctrlbit, 1);
+ if (clk->ctrlbit != 0)
+ s3c2410_clk_enable(clk->ctrlbit, 1);
+
return 0;
}
@@ -240,6 +242,10 @@ static struct clk init_clocks[] = {
{ .name = "spi",
.parent = &clk_p,
.ctrlbit = S3C2410_CLKCON_SPI
+ },
+ { .name = "watchdog",
+ .parent = &clk_p,
+ .ctrlbit = 0
}
};
@@ -284,10 +290,10 @@ static int __init s3c2410_init_clocks(void)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c2410_register_clock(&clk_h) < 0)
- printk(KERN_ERR "failed to register cpu fclk\n");
+ printk(KERN_ERR "failed to register cpu hclk\n");
if (s3c2410_register_clock(&clk_p) < 0)
- printk(KERN_ERR "failed to register cpu fclk\n");
+ printk(KERN_ERR "failed to register cpu pclk\n");
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
ret = s3c2410_register_clock(clkp);
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
index e1c44d656a361..f6316bcef90c7 100644
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/mach-s3c2410/devs.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*
* Modifications:
+ * 21-Aug-2004 BJD Added IRQ_TICK to RTC resources
* 18-Aug-2004 BJD Created initial version
*/
@@ -229,8 +230,12 @@ static struct resource s3c_rtc_resource[] = {
.start = IRQ_RTC,
.end = IRQ_RTC,
.flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = IRQ_TICK,
+ .end = IRQ_TICK,
+ .flags = IORESOURCE_IRQ
}
-
};
struct platform_device s3c_device_rtc = {
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 2268ab3c7c699..e089dfed457be 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/mach-bast.c
*
- * Copyright (c) 2003 Simtec Electronics
+ * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://www.simtec.co.uk/products/EB2410ITX/
@@ -10,6 +10,8 @@
* published by the Free Software Foundation.
*
* Modifications:
+ * 20-Aug-2004 BJD Added s3c2410_board struct
+ * 18-Aug-2004 BJD Added platform devices from default set
* 16-May-2003 BJD Created initial version
* 16-Aug-2003 BJD Fixed header files and copyright, added URL
* 05-Sep-2003 BJD Moved to v2.6 kernel
@@ -23,6 +25,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/device.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -39,6 +42,7 @@
#include <asm/arch/regs-serial.h>
#include "s3c2410.h"
+#include "devs.h"
/* macros for virtual address mods for the io space entries */
#define VA_C5(item) ((item) + BAST_VAM_CS5)
@@ -154,6 +158,7 @@ static struct s3c2410_uartcfg bast_uartcfgs[] = {
[1] = {
.hwport = 1,
.flags = 0,
+
.clock = &bast_serial_clock,
.ucon = UCON,
.ulcon = ULCON,
@@ -170,19 +175,30 @@ static struct s3c2410_uartcfg bast_uartcfgs[] = {
}
};
+static struct platform_device *bast_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+};
+
+static struct s3c2410_board bast_board __initdata = {
+ .devices = bast_devices,
+ .devices_count = ARRAY_SIZE(bast_devices)
+};
void __init bast_map_io(void)
{
s3c2410_map_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
s3c2410_uartcfgs = bast_uartcfgs;
+
+ s3c2410_set_board(&bast_board);
}
void __init bast_init_irq(void)
{
- //llprintk("bast_init_irq:\n");
-
s3c2410_init_irq();
-
}
void __init bast_init_time(void)
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 0a9ba135bb298..7b42aa9e8c022 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -1,6 +1,6 @@
-/* linux/arch/arm/mach-s3c2410/mach-ipaq.c
+/* linux/arch/arm/mach-s3c2410/mach-h1940.c
*
- * Copyright (c) 2003 Simtec Electronics
+ * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://www.handhelds.org/projects/h1940.html
@@ -16,6 +16,7 @@
* 06-Jan-2003 BJD Updates for <arch/map.h>
* 18-Jan-2003 BJD Added serial port configuration
* 17-Feb-2003 BJD Copied to mach-ipaq.c
+ * 21-Aug-2004 BJD Added struct s3c2410_board
*/
#include <linux/kernel.h>
@@ -39,6 +40,7 @@
#include <asm/arch/regs-serial.h>
#include "s3c2410.h"
+#include "devs.h"
static struct map_desc ipaq_iodesc[] __initdata = {
/* nothing here yet */
@@ -77,10 +79,27 @@ static struct s3c2410_uartcfg ipaq_uartcfgs[] = {
};
+
+
+static struct platform_device *h1940_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+};
+
+static struct s3c2410_board h1940_board __initdata = {
+ .devices = h1940_devices,
+ .devices_count = ARRAY_SIZE(h1940_devices)
+};
+
void __init ipaq_map_io(void)
{
s3c2410_map_io(ipaq_iodesc, ARRAY_SIZE(ipaq_iodesc));
s3c2410_uartcfgs = ipaq_uartcfgs;
+
+ s3c2410_set_board(&h1940_board);
}
void __init ipaq_init_irq(void)
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index bfadbd4254f83..a618355fb2047 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -47,7 +47,7 @@
#include <asm/arch/regs-serial.h>
#include "s3c2410.h"
-
+#include "devs.h"
static struct map_desc smdk2410_iodesc[] __initdata = {
/* nothing here yet */
@@ -87,11 +87,25 @@ static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
}
};
+static struct platform_device *smdk2410_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+};
+
+static struct s3c2410_board smdk2410_board __initdata = {
+ .devices = smdk2410_devices,
+ .devices_count = ARRAY_SIZE(smdk2410_devices)
+};
void __init smdk2410_map_io(void)
{
s3c2410_map_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
s3c2410_uartcfgs = smdk2410_uartcfgs;
+
+ s3c2410_set_board(&smdk2410_board);
}
void __init smdk2410_init_irq(void)
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index aae341c6908fe..3219108db33e0 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -11,13 +11,8 @@
* published by the Free Software Foundation.
*
* Modifications:
+ * 21-Aug-2004 BJD Added struct s3c2410_board
* 06-Aug-2004 BJD Fixed call to time initialisation
- * 12-Jul-2004 BJD Renamed machine
- * 16-May-2003 BJD Created initial version
- * 16-Aug-2003 BJD Fixed header files and copyright, added URL
- * 05-Sep-2003 BJD Moved to v2.6 kernel
- * 06-Jan-2003 BJD Updates for <arch/map.h>
- * 18-Jan-2003 BJD Added serial port configuration
* 05-Apr-2004 BJD Copied to make mach-vr1000.c
*/
@@ -44,6 +39,7 @@
#include <asm/arch/regs-serial.h>
#include "s3c2410.h"
+#include "devs.h"
/* macros for virtual address mods for the io space entries */
#define VA_C5(item) ((item) + BAST_VAM_CS5)
@@ -143,11 +139,26 @@ static struct s3c2410_uartcfg vr1000_uartcfgs[] = {
}
};
+static struct platform_device *vr1000_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+};
+
+static struct s3c2410_board vr1000_board __initdata = {
+ .devices = vr1000_devices,
+ .devices_count = ARRAY_SIZE(vr1000_devices)
+};
+
void __init vr1000_map_io(void)
{
s3c2410_map_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
s3c2410_uartcfgs = vr1000_uartcfgs;
+
+ s3c2410_set_board(&vr1000_board);
}
void __init vr1000_init_irq(void)
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index bfd843cef69bf..09dbcff0d4a7f 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/s3c2410.c
*
- * Copyright (c) 2003 Simtec Electronics
+ * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://www.simtec.co.uk/products/EB2410ITX/
@@ -13,7 +13,8 @@
* 16-May-2003 BJD Created initial version
* 16-Aug-2003 BJD Fixed header files and copyright, added URL
* 05-Sep-2003 BJD Moved to kernel v2.6
- * 18-Jan-2003 BJD Added serial port configuration
+ * 18-Jan-2004 BJD Added serial port configuration
+ * 21-Aug-2004 BJD Added new struct s3c2410_board handler
*/
#include <linux/kernel.h>
@@ -35,6 +36,8 @@
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-serial.h>
+#include "s3c2410.h"
+
int s3c2410_clock_tick_rate = 12*1000*1000; /* current timers at 12MHz */
/* serial port setup */
@@ -56,24 +59,15 @@ unsigned long s3c2410_pclk;
#define IODESC_ENT(x) { S3C2410_VA_##x, S3C2410_PA_##x, S3C2410_SZ_##x, MT_DEVICE }
static struct map_desc s3c2410_iodesc[] __initdata = {
- IODESC_ENT(IRQ),
- IODESC_ENT(MEMCTRL),
- IODESC_ENT(USBHOST),
- IODESC_ENT(DMA),
- IODESC_ENT(CLKPWR),
- IODESC_ENT(LCD),
- IODESC_ENT(NAND),
- IODESC_ENT(UART),
- IODESC_ENT(TIMER),
- IODESC_ENT(USBDEV),
- IODESC_ENT(WATCHDOG),
- IODESC_ENT(IIC),
- IODESC_ENT(IIS),
- IODESC_ENT(GPIO),
- IODESC_ENT(RTC),
- IODESC_ENT(ADC),
- IODESC_ENT(SPI),
- IODESC_ENT(SDI)
+ IODESC_ENT(IRQ),
+ IODESC_ENT(MEMCTRL),
+ IODESC_ENT(USBHOST),
+ IODESC_ENT(CLKPWR),
+ IODESC_ENT(LCD),
+ IODESC_ENT(UART),
+ IODESC_ENT(TIMER),
+ IODESC_ENT(GPIO),
+ IODESC_ENT(ADC),
};
static struct resource s3c_uart0_resource[] = {
@@ -175,6 +169,12 @@ void __init s3c2410_map_io(struct map_desc *mach_desc, int size)
print_mhz(s3c2410_pclk));
}
+static struct s3c2410_board *board;
+
+void s3c2410_set_board(struct s3c2410_board *b)
+{
+ board = b;
+}
static int __init s3c2410_init(void)
{
@@ -183,6 +183,22 @@ static int __init s3c2410_init(void)
printk("S3C2410: Initialising architecture\n");
ret = platform_add_devices(uart_devices, ARRAY_SIZE(uart_devices));
+ if (ret)
+ return ret;
+
+ if (board != NULL) {
+ if (board->devices != NULL) {
+ ret = platform_add_devices(board->devices,
+ board->devices_count);
+
+ if (ret) {
+ printk(KERN_ERR "s3c2410: failed to add board devices (%d)\n", ret);
+ }
+ }
+
+ /* not adding board devices may not be fatal */
+ ret = 0;
+ }
return ret;
}
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h
index cc139f43ede0d..3f0c9d620807c 100644
--- a/arch/arm/mach-s3c2410/s3c2410.h
+++ b/arch/arm/mach-s3c2410/s3c2410.h
@@ -11,7 +11,7 @@
*
* Modifications:
* 18-Aug-2004 BJD Created initial version
- *
+ * 20-Aug-2004 BJD Added s3c2410_board struct
*/
extern void s3c2410_map_io(struct map_desc *, int count);
@@ -20,3 +20,16 @@ extern void s3c2410_init_irq(void);
extern void s3c2410_init_time(void);
+/* the board structure is used at first initialsation time
+ * to get info such as the devices to register for this
+ * board. This is done because platfrom_add_devices() cannot
+ * be called from the map_io entry.
+ *
+*/
+
+struct s3c2410_board {
+ struct platform_device **devices;
+ unsigned int devices_count;
+};
+
+extern void s3c2410_set_board(struct s3c2410_board *board);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index cc2f7a8b3f292..bbf23e1bc3361 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -495,7 +495,7 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
*/
arch_adjust_zones(node, zone_size, zhole_size);
- free_area_init_node(node, pgdat, NULL, zone_size,
+ free_area_init_node(node, pgdat, zone_size,
bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
}
diff --git a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c
index 2ad457558681d..95fb63fa9d181 100644
--- a/arch/arm/nwfpe/fpa11_cpdt.c
+++ b/arch/arm/nwfpe/fpa11_cpdt.c
@@ -42,8 +42,13 @@ static inline void loadDouble(const unsigned int Fn, const unsigned int __user *
unsigned int *p;
p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
fpa11->fType[Fn] = typeDouble;
+#ifdef __ARMEB__
+ get_user(p[0], &pMem[0]); /* sign & exponent */
+ get_user(p[1], &pMem[1]);
+#else
get_user(p[0], &pMem[1]);
get_user(p[1], &pMem[0]); /* sign & exponent */
+#endif
}
#ifdef CONFIG_FPE_NWFPE_XP
@@ -140,8 +145,13 @@ static inline void storeDouble(const unsigned int Fn, unsigned int __user *pMem)
val.f = fpa11->fpreg[Fn].fDouble;
}
+#ifdef __ARMEB__
+ put_user(val.i[0], &pMem[0]); /* msw */
+ put_user(val.i[1], &pMem[1]); /* lsw */
+#else
put_user(val.i[1], &pMem[0]); /* msw */
put_user(val.i[0], &pMem[1]); /* lsw */
+#endif
}
#ifdef CONFIG_FPE_NWFPE_XP
diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c
index be689db15456a..d77e18fa71bc8 100644
--- a/arch/arm/oprofile/op_model_xscale.c
+++ b/arch/arm/oprofile/op_model_xscale.c
@@ -30,6 +30,7 @@
#define PMN_RESET 0x002 /* Reset event counters */
#define CCNT_RESET 0x004 /* Reset clock counter */
#define PMU_RESET (CCNT_RESET | PMN_RESET)
+#define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */
/* TODO do runtime detection */
#ifdef CONFIG_ARCH_IOP310
@@ -125,12 +126,15 @@ static struct pmu_type *pmu;
static void write_pmnc(u32 val)
{
- /* upper 4bits and 7, 11 are write-as-0 */
- val &= 0xffff77f;
- if (pmu->id == PMU_XSC1)
+ if (pmu->id == PMU_XSC1) {
+ /* upper 4bits and 7, 11 are write-as-0 */
+ val &= 0xffff77f;
__asm__ __volatile__ ("mcr p14, 0, %0, c0, c0, 0" : : "r" (val));
- else
+ } else {
+ /* bits 4-23 are write-as-0, 24-31 are write ignored */
+ val &= 0xf;
__asm__ __volatile__ ("mcr p14, 0, %0, c0, c1, 0" : : "r" (val));
+ }
}
static u32 read_pmnc(void)
@@ -139,8 +143,11 @@ static u32 read_pmnc(void)
if (pmu->id == PMU_XSC1)
__asm__ __volatile__ ("mrc p14, 0, %0, c0, c0, 0" : "=r" (val));
- else
+ else {
__asm__ __volatile__ ("mrc p14, 0, %0, c0, c1, 0" : "=r" (val));
+ /* bits 1-2 and 4-23 are read-unpredictable */
+ val &= 0xff000009;
+ }
return val;
}
@@ -386,8 +393,10 @@ static int xscale_pmu_start(void)
if (pmu->id == PMU_XSC1)
pmnc |= pmu->int_enable;
- else
+ else {
__asm__ __volatile__ ("mcr p14, 0, %0, c4, c1, 0" : : "r" (pmu->int_enable));
+ pmnc &= ~PMU_CNT64;
+ }
pmnc |= PMU_ENABLE;
write_pmnc(pmnc);
diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c
index 16cf7db5cc46b..bf05f1537aa1a 100644
--- a/arch/arm26/kernel/signal.c
+++ b/arch/arm26/kernel/signal.c
@@ -465,9 +465,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
return;
}
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, tsk);
+ force_sigsegv(sig, tsk);
}
/*
diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c
index 0d1cdd503f3b5..431f9f85e0693 100644
--- a/arch/arm26/kernel/sys_arm.c
+++ b/arch/arm26/kernel/sys_arm.c
@@ -256,7 +256,7 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct
if (!newsp)
newsp = regs->ARM_sp;
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL);
+ return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
}
asmlinkage int sys_vfork(struct pt_regs *regs)
diff --git a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
index 61eedf0bc42f2..cbbda2766ffd1 100644
--- a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
+++ b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
@@ -34,9 +34,6 @@ SECTIONS
__early_begin = .;
*(__early_param)
__early_end = .;
- __start___param = .;
- *(__param)
- __stop___param = .;
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
diff --git a/arch/arm26/kernel/vmlinux-arm26.lds.in b/arch/arm26/kernel/vmlinux-arm26.lds.in
index 2393f3805a498..128eb91954069 100644
--- a/arch/arm26/kernel/vmlinux-arm26.lds.in
+++ b/arch/arm26/kernel/vmlinux-arm26.lds.in
@@ -35,9 +35,6 @@ SECTIONS
__early_begin = .;
*(__early_param)
__early_end = .;
- __start___param = .;
- *(__param)
- __stop___param = .;
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c
index ad41cebe207a9..ae5ced10d987d 100644
--- a/arch/arm26/mm/init.c
+++ b/arch/arm26/mm/init.c
@@ -305,8 +305,8 @@ void __init paging_init(struct meminfo *mi)
(bdata->node_boot_start >> PAGE_SHIFT);
if (!zone_size[0])
BUG();
-
- free_area_init_node(0, pgdat, 0, zone_size,
+ pgdat->node_mem_map = NULL;
+ free_area_init_node(0, pgdat, zone_size,
bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
mem_map = NODE_DATA(0)->node_mem_map;
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index 8aba42472912d..d0993bf720183 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -180,7 +180,7 @@ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
{
if (!newusp)
newusp = rdusp();
- return do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0, parent_tid, child_tid);
+ return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
}
/* vfork is a system call in i386 because of register-pressure - maybe
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 8db985e296fb1..19f93fe42d963 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -409,9 +409,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -475,9 +473,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c
index df03dea5bae4b..720b9c1561ddc 100644
--- a/arch/cris/arch-v10/mm/init.c
+++ b/arch/cris/arch-v10/mm/init.c
@@ -183,7 +183,7 @@ paging_init(void)
* mem_map page array.
*/
- free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
+ free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
mem_map = contig_page_data.node_mem_map;
}
diff --git a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S
index 6b73a2c0dad85..9e134c688363c 100644
--- a/arch/cris/arch-v10/vmlinux.lds.S
+++ b/arch/cris/arch-v10/vmlinux.lds.S
@@ -64,9 +64,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
.initcall.init : {
__initcall_start = .;
*(.initcall1.init);
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index d7c058d64030e..134aec1c6d199 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -189,7 +189,7 @@ asmlinkage int h8300_clone(struct pt_regs *regs)
newsp = regs->er2;
if (!newsp)
newsp = rdusp();
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL);
+ return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
}
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index 17c83890c22a3..5fd383a6af841 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -391,9 +391,7 @@ static void setup_frame (int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -443,9 +441,7 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static inline void
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index 7a6009cf26d24..427f1891c7261 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -150,9 +150,6 @@ SECTIONS
*(.init.setup)
. = ALIGN(0x4) ;
___setup_end = .;
- ___start___param = .;
- *(__param)
- ___stop___param = .;
___initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug
index 16b0b7ff7fccf..ded1c2c1a087e 100644
--- a/arch/i386/Kconfig.debug
+++ b/arch/i386/Kconfig.debug
@@ -45,6 +45,18 @@ config 4KSTACKS
on the VM subsystem for higher order allocations. This option
will also use IRQ stacks to compensate for the reduced stackspace.
+config SCHEDSTATS
+ bool "Collect scheduler statistics"
+ depends on DEBUG_KERNEL && PROC_FS
+ help
+ If you say Y here, additional code will be inserted into the
+ scheduler and related routines to collect statistics about
+ scheduler behavior and provide them in /proc/schedstat. These
+ stats may be useful for both tuning and debugging the scheduler
+ If you aren't debugging the scheduler or trying to tune a specific
+ application, you can say N to avoid the very slight overhead
+ this adds.
+
config X86_FIND_SMP_CONFIG
bool
depends on X86_LOCAL_APIC || X86_VOYAGER
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index e03816e72f506..b68579f15729c 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -47,12 +47,14 @@ quiet_cmd_syscall = SYSCALL $@
cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
-Wl,-T,$(filter-out FORCE,$^) -o $@
+export AFLAGS_vsyscall.lds.o += -P -C -U$(ARCH)
+
vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1
SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags)
SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags)
$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
-$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds.s $(obj)/vsyscall-%.o FORCE
$(call if_changed,syscall)
# We also create a special relocatable object that should mirror the symbol
@@ -63,5 +65,5 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o
$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
SYSCFLAGS_vsyscall-syms.o = -r
-$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE
+$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds.s $(obj)/vsyscall-sysenter.o FORCE
$(call if_changed,syscall)
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 607da069d372e..32d4b331fe714 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -343,7 +343,7 @@ void __init init_bsp_APIC(void)
void __init setup_local_APIC (void)
{
- unsigned long value, ver, maxlvt;
+ unsigned long oldvalue, value, ver, maxlvt;
/* Pound the ESR really hard over the head with a big hammer - mbligh */
if (esr_disable) {
@@ -459,9 +459,7 @@ void __init setup_local_APIC (void)
maxlvt = get_maxlvt();
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0);
- value = apic_read(APIC_ESR);
- apic_printk(APIC_VERBOSE, "ESR value before enabling vector:"
- " %08lx\n", value);
+ oldvalue = apic_read(APIC_ESR);
value = ERROR_APIC_VECTOR; // enables sending errors
apic_write_around(APIC_LVTERR, value);
@@ -471,8 +469,10 @@ void __init setup_local_APIC (void)
if (maxlvt > 3)
apic_write(APIC_ESR, 0);
value = apic_read(APIC_ESR);
- apic_printk(APIC_VERBOSE, "ESR value after enabling vector:"
- " %08lx\n", value);
+ if (value != oldvalue)
+ apic_printk(APIC_VERBOSE, "ESR value before enabling "
+ "vector: 0x%08lx after: 0x%08lx\n",
+ oldvalue, value);
} else {
if (esr_disable)
/*
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 3bfc2cbb84643..4cafb2e99ef42 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -2271,10 +2271,12 @@ static int __init apm_init(void)
}
if ((num_online_cpus() > 1) && !power_off && !smp) {
printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+ apm_info.disabled = 1;
return -ENODEV;
}
if (PM_IS_ACTIVE()) {
printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+ apm_info.disabled = 1;
return -ENODEV;
}
pm_active = 1;
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 428800f11afc7..89dc79a655059 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -559,13 +559,11 @@ void __init cpu_init (void)
load_esp0(t, thread);
set_tss_desc(cpu,t);
- per_cpu(cpu_gdt_table,cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff;
load_TR_desc();
load_LDT(&init_mm.context);
/* Set up doublefault TSS pointer in the GDT */
__set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
- per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff;
/* Clear %fs and %gs. */
asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index b3bcde8c0ec5c..e243f0fdd20f3 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -38,6 +38,17 @@
#define PFX "longhaul: "
+#define TYPE_LONGHAUL_V1 1
+#define TYPE_LONGHAUL_V2 2
+#define TYPE_POWERSAVER 3
+
+#define CPU_SAMUEL 1
+#define CPU_SAMUEL2 2
+#define CPU_EZRA 3
+#define CPU_EZRA_T 4
+#define CPU_NEHEMIAH 5
+
+static int cpu_model;
static unsigned int numscales=16, numvscales;
static unsigned int fsb;
static int minvid, maxvid;
@@ -73,9 +84,23 @@ static int voltage_table[32];
static unsigned int highest_speed, lowest_speed; /* kHz */
static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table;
+static char speedbuffer[8];
+
+static char *print_speed(int speed)
+{
+ if (speed > 1000) {
+ if (speed%1000 == 0)
+ sprintf (speedbuffer, "%dGHz", speed/1000);
+ else
+ sprintf (speedbuffer, "%d.%dGHz", speed/1000, (speed%1000)/100);
+ } else
+ sprintf (speedbuffer, "%dMHz", speed);
+
+ return speedbuffer;
+}
-static unsigned int calc_speed(int mult, int fsb)
+static unsigned int calc_speed(int mult)
{
int khz;
khz = (mult/10)*fsb;
@@ -92,7 +117,7 @@ static int longhaul_get_cpu_mult(void)
rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
- if (longhaul_version==2 || longhaul_version==3) {
+ if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) {
if (lo & (1<<27))
invalue+=16;
}
@@ -101,8 +126,21 @@ static int longhaul_get_cpu_mult(void)
static void do_powersaver(union msr_longhaul *longhaul,
- unsigned int clock_ratio_index, int version)
+ unsigned int clock_ratio_index)
{
+ int version;
+
+ switch (cpu_model) {
+ case CPU_EZRA_T:
+ version = 3;
+ break;
+ case CPU_NEHEMIAH:
+ version = 0xf;
+ break;
+ default:
+ return;
+ }
+
rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf;
longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
@@ -125,7 +163,7 @@ static void do_powersaver(union msr_longhaul *longhaul,
* longhaul_set_cpu_frequency()
* @clock_ratio_index : bitpattern of the new multiplier.
*
- * Sets a new clock ratio, and -if applicable- a new Front Side Bus
+ * Sets a new clock ratio.
*/
static void longhaul_setstate(unsigned int clock_ratio_index)
@@ -134,22 +172,28 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
struct cpufreq_freqs freqs;
union msr_longhaul longhaul;
union msr_bcr2 bcr2;
+ static unsigned int old_ratio=-1;
+
+ if (old_ratio == clock_ratio_index)
+ return;
+ old_ratio = clock_ratio_index;
mult = clock_ratio[clock_ratio_index];
if (mult == -1)
return;
- speed = calc_speed (mult, fsb);
+ speed = calc_speed(mult);
if ((speed > highest_speed) || (speed < lowest_speed))
return;
- freqs.old = calc_speed (longhaul_get_cpu_mult(), fsb);
+ freqs.old = calc_speed(longhaul_get_cpu_mult());
freqs.new = speed;
freqs.cpu = 0; /* longhaul.c is UP only driver */
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb, mult/10, mult%10);
+ dprintk (KERN_INFO PFX "Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
+ fsb, mult/10, mult%10, print_speed(speed/1000));
switch (longhaul_version) {
@@ -160,7 +204,8 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
* *NB* Until we get voltage scaling working v1 & v2 are the same code.
* Longhaul v2 appears in Samuel2 Steppings 1->7 [C5b] and Ezra [C5C]
*/
- case 1:
+ case TYPE_LONGHAUL_V1:
+ case TYPE_LONGHAUL_V2:
rdmsrl (MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */
bcr2.bits.ESOFTBF = 1;
@@ -180,26 +225,18 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
break;
/*
- * Longhaul v3 (aka Powersaver). (Ezra-T [C5M])
+ * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N])
* We can scale voltage with this too, but that's currently
* disabled until we come up with a decent 'match freq to voltage'
* algorithm.
* When we add voltage scaling, we will also need to do the
* voltage/freq setting in order depending on the direction
* of scaling (like we do in powernow-k7.c)
- */
- case 2:
- do_powersaver(&longhaul, clock_ratio_index, 3);
- break;
-
- /*
- * Powersaver. (Nehemiah [C5N])
- * As for Ezra-T, we don't do voltage yet.
- * This can do FSB scaling too, but it has never been proven
+ * Nehemiah can do FSB scaling too, but this has never been proven
* to work in practice.
*/
- case 3:
- do_powersaver(&longhaul, clock_ratio_index, 0xf);
+ case TYPE_POWERSAVER:
+ do_powersaver(&longhaul, clock_ratio_index);
break;
}
@@ -249,7 +286,6 @@ static int guess_fsb(void)
static int __init longhaul_get_ranges(void)
{
- struct cpuinfo_x86 *c = cpu_data;
unsigned long invalue;
unsigned int multipliers[32]= {
50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
@@ -261,62 +297,66 @@ static int __init longhaul_get_ranges(void)
unsigned int eblcr_fsb_table_v2[] = { 133, 100, -1, 66 };
switch (longhaul_version) {
- case 1:
+ case TYPE_LONGHAUL_V1:
+ case TYPE_LONGHAUL_V2:
/* Ugh, Longhaul v1 didn't have the min/max MSRs.
Assume min=3.0x & max = whatever we booted at. */
minmult = 30;
maxmult = longhaul_get_cpu_mult();
rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
invalue = (lo & (1<<18|1<<19)) >>18;
- if (c->x86_model==6)
+ if (cpu_model==CPU_SAMUEL || cpu_model==CPU_SAMUEL2)
fsb = eblcr_fsb_table_v1[invalue];
else
fsb = guess_fsb();
break;
- case 2:
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-
- invalue = longhaul.bits.MaxMHzBR;
- if (longhaul.bits.MaxMHzBR4)
- invalue += 16;
- maxmult=multipliers[invalue];
-
- invalue = longhaul.bits.MinMHzBR;
- if (longhaul.bits.MinMHzBR4 == 1)
- minmult = 30;
- else
- minmult = multipliers[invalue];
-
- fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
- break;
-
- case 3:
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
-
- /*
- * TODO: This code works, but raises a lot of questions.
- * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.
- * We get around this by using a hardcoded multiplier of 5.0x
- * for the minimimum speed, and the speed we booted up at for the max.
- * This is done in longhaul_get_cpu_mult() by reading the EBLCR register.
- * - According to some VIA documentation EBLCR is only
- * in pre-Nehemiah C3s. How this still works is a mystery.
- * We're possibly using something undocumented and unsupported,
- * But it works, so we don't grumble.
- */
- minmult=50;
- maxmult=longhaul_get_cpu_mult();
-
- /* Starting with the 1.2GHz parts, theres a 200MHz bus. */
- if ((cpu_khz/1000) > 1200)
- fsb = 200;
- else
+ case TYPE_POWERSAVER:
+ /* Ezra-T */
+ if (cpu_model==CPU_EZRA_T) {
+ rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+ invalue = longhaul.bits.MaxMHzBR;
+ if (longhaul.bits.MaxMHzBR4)
+ invalue += 16;
+ maxmult=multipliers[invalue];
+
+ invalue = longhaul.bits.MinMHzBR;
+ if (longhaul.bits.MinMHzBR4 == 1)
+ minmult = 30;
+ else
+ minmult = multipliers[invalue];
fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
- break;
+ break;
+ }
+
+ /* Nehemiah */
+ if (cpu_model==CPU_NEHEMIAH) {
+ rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+
+ /*
+ * TODO: This code works, but raises a lot of questions.
+ * - Some Nehemiah's seem to have broken Min/MaxMHzBR's.
+ * We get around this by using a hardcoded multiplier of 4.0x
+ * for the minimimum speed, and the speed we booted up at for the max.
+ * This is done in longhaul_get_cpu_mult() by reading the EBLCR register.
+ * - According to some VIA documentation EBLCR is only
+ * in pre-Nehemiah C3s. How this still works is a mystery.
+ * We're possibly using something undocumented and unsupported,
+ * But it works, so we don't grumble.
+ */
+ minmult=40;
+ maxmult=longhaul_get_cpu_mult();
+
+ /* Starting with the 1.2GHz parts, theres a 200MHz bus. */
+ if ((cpu_khz/1000) > 1200)
+ fsb = 200;
+ else
+ fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
+ break;
+ }
}
- dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n",
+ dprintk (KERN_INFO PFX "MinMult:%d.%dx MaxMult:%d.%dx\n",
minmult/10, minmult%10, maxmult/10, maxmult%10);
if (fsb == -1) {
@@ -324,10 +364,11 @@ static int __init longhaul_get_ranges(void)
return -EINVAL;
}
- highest_speed = calc_speed (maxmult, fsb);
- lowest_speed = calc_speed (minmult,fsb);
- dprintk (KERN_INFO PFX "FSB: %dMHz Lowestspeed=%dMHz Highestspeed=%dMHz\n",
- fsb, lowest_speed/1000, highest_speed/1000);
+ highest_speed = calc_speed(maxmult);
+ lowest_speed = calc_speed(minmult);
+ dprintk (KERN_INFO PFX "FSB:%dMHz ", fsb);
+ dprintk ("Lowest speed:%s ", print_speed(lowest_speed/1000));
+ dprintk ("Highest speed:%s\n", print_speed(highest_speed/1000));
if (lowest_speed == highest_speed) {
printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n");
@@ -350,7 +391,7 @@ static int __init longhaul_get_ranges(void)
continue;
if (ratio > maxmult || ratio < minmult)
continue;
- longhaul_table[k].frequency = calc_speed (ratio, fsb);
+ longhaul_table[k].frequency = calc_speed(ratio);
longhaul_table[k].index = j;
k++;
}
@@ -426,8 +467,7 @@ static int longhaul_verify(struct cpufreq_policy *policy)
static int longhaul_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
+ unsigned int target_freq, unsigned int relation)
{
unsigned int table_index = 0;
unsigned int new_clock_ratio = 0;
@@ -442,13 +482,15 @@ static int longhaul_target(struct cpufreq_policy *policy,
return 0;
}
+
static unsigned int longhaul_get(unsigned int cpu)
{
if (cpu)
return 0;
- return (calc_speed (longhaul_get_cpu_mult(), fsb));
+ return calc_speed(longhaul_get_cpu_mult());
}
+
static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
@@ -457,26 +499,31 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
switch (c->x86_model) {
case 6:
+ cpu_model = CPU_SAMUEL;
cpuname = "C3 'Samuel' [C5A]";
- longhaul_version=1;
+ longhaul_version = TYPE_LONGHAUL_V1;
memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));
memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
break;
- case 7: /* C5B / C5C */
- longhaul_version=1;
+ case 7:
+ longhaul_version = TYPE_LONGHAUL_V1;
switch (c->x86_mask) {
case 0:
+ cpu_model = CPU_SAMUEL2;
cpuname = "C3 'Samuel 2' [C5B]";
/* Note, this is not a typo, early Samuel2's had Samuel1 ratios. */
memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));
memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));
break;
case 1 ... 15:
- if (c->x86_mask < 8)
+ if (c->x86_mask < 8) {
+ cpu_model = CPU_SAMUEL2;
cpuname = "C3 'Samuel 2' [C5B]";
- else
+ } else {
+ cpu_model = CPU_EZRA;
cpuname = "C3 'Ezra' [C5C]";
+ }
memcpy (clock_ratio, ezra_clock_ratio, sizeof(ezra_clock_ratio));
memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));
break;
@@ -484,15 +531,17 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
break;
case 8:
+ cpu_model = CPU_EZRA_T;
cpuname = "C3 'Ezra-T' [C5M]";
- longhaul_version=2;
+ longhaul_version = TYPE_POWERSAVER;
numscales=32;
memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));
memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));
break;
case 9:
- longhaul_version=3;
+ cpu_model = CPU_NEHEMIAH;
+ longhaul_version = TYPE_POWERSAVER;
numscales=32;
switch (c->x86_mask) {
case 0 ... 1:
@@ -518,19 +567,28 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
break;
}
- printk (KERN_INFO PFX "VIA %s CPU detected. Longhaul v%d supported.\n",
- cpuname, longhaul_version);
+ printk (KERN_INFO PFX "VIA %s CPU detected. ", cpuname);
+ switch (longhaul_version) {
+ case TYPE_LONGHAUL_V1:
+ case TYPE_LONGHAUL_V2:
+ printk ("Longhaul v%d supported.\n", longhaul_version);
+ break;
+ case TYPE_POWERSAVER:
+ printk ("Powersaver supported.\n");
+ break;
+ };
ret = longhaul_get_ranges();
if (ret != 0)
return ret;
- if ((longhaul_version==2) && (dont_scale_voltage==0))
+ if ((longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) &&
+ (dont_scale_voltage==0))
longhaul_setup_voltagescaling();
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
- policy->cur = calc_speed (longhaul_get_cpu_mult(), fsb);
+ policy->cur = calc_speed(longhaul_get_cpu_mult());
ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
if (ret)
@@ -563,6 +621,7 @@ static struct cpufreq_driver longhaul_driver = {
.attr = longhaul_attr,
};
+
static int __init longhaul_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
@@ -580,16 +639,17 @@ static int __init longhaul_init(void)
return -ENODEV;
}
+
static void __exit longhaul_exit(void)
{
int i=0;
- unsigned int new_clock_ratio;
-
- while (clock_ratio[i] != maxmult)
- i++;
- new_clock_ratio = longhaul_table[i].index & 0xFF;
- longhaul_setstate(new_clock_ratio);
+ for (i=0; i < numscales; i++) {
+ if (clock_ratio[i] == maxmult) {
+ longhaul_setstate(i);
+ break;
+ }
+ }
cpufreq_unregister_driver(&longhaul_driver);
kfree(longhaul_table);
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 29a3326897ca1..d13f9bb470df0 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -72,44 +72,44 @@ struct _cache_table
/* all the cache descriptor types we care about (no TLB or trace cache entries) */
static struct _cache_table cache_table[] __initdata =
{
- { 0x06, LVL_1_INST, 8 },
- { 0x08, LVL_1_INST, 16 },
- { 0x0a, LVL_1_DATA, 8 },
- { 0x0c, LVL_1_DATA, 16 },
- { 0x22, LVL_3, 512 },
- { 0x23, LVL_3, 1024 },
- { 0x25, LVL_3, 2048 },
- { 0x29, LVL_3, 4096 },
- { 0x2c, LVL_1_DATA, 32 },
- { 0x30, LVL_1_INST, 32 },
- { 0x39, LVL_2, 128 },
- { 0x3b, LVL_2, 128 },
- { 0x3c, LVL_2, 256 },
- { 0x41, LVL_2, 128 },
- { 0x42, LVL_2, 256 },
- { 0x43, LVL_2, 512 },
- { 0x44, LVL_2, 1024 },
- { 0x45, LVL_2, 2048 },
- { 0x60, LVL_1_DATA, 16 },
- { 0x66, LVL_1_DATA, 8 },
- { 0x67, LVL_1_DATA, 16 },
- { 0x68, LVL_1_DATA, 32 },
- { 0x70, LVL_TRACE, 12 },
- { 0x71, LVL_TRACE, 16 },
- { 0x72, LVL_TRACE, 32 },
- { 0x78, LVL_2, 1024 },
- { 0x79, LVL_2, 128 },
- { 0x7a, LVL_2, 256 },
- { 0x7b, LVL_2, 512 },
- { 0x7c, LVL_2, 1024 },
- { 0x7d, LVL_2, 2048 },
- { 0x7f, LVL_2, 512 },
- { 0x82, LVL_2, 256 },
- { 0x83, LVL_2, 512 },
- { 0x84, LVL_2, 1024 },
- { 0x85, LVL_2, 2048 },
- { 0x86, LVL_2, 512 },
- { 0x87, LVL_2, 1024 },
+ { 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 */
+ { 0x0a, LVL_1_DATA, 8 }, /* 2 way set assoc, 32 byte line size */
+ { 0x0c, LVL_1_DATA, 16 }, /* 4-way set assoc, 32 byte line size */
+ { 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */
+ { 0x23, LVL_3, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x25, LVL_3, 2048 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x29, LVL_3, 4096 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x2c, LVL_1_DATA, 32 }, /* 8-way set assoc, 64 byte line size */
+ { 0x30, LVL_1_INST, 32 }, /* 8-way set assoc, 64 byte line size */
+ { 0x39, LVL_2, 128 }, /* 4-way set assoc, sectored cache, 64 byte line size */
+ { 0x3b, LVL_2, 128 }, /* 2-way set assoc, sectored cache, 64 byte line size */
+ { 0x3c, LVL_2, 256 }, /* 4-way set assoc, sectored cache, 64 byte line size */
+ { 0x41, LVL_2, 128 }, /* 4-way set assoc, 32 byte line size */
+ { 0x42, LVL_2, 256 }, /* 4-way set assoc, 32 byte line size */
+ { 0x43, LVL_2, 512 }, /* 4-way set assoc, 32 byte line size */
+ { 0x44, LVL_2, 1024 }, /* 4-way set assoc, 32 byte line size */
+ { 0x45, LVL_2, 2048 }, /* 4-way set assoc, 32 byte line size */
+ { 0x60, LVL_1_DATA, 16 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x66, LVL_1_DATA, 8 }, /* 4-way set assoc, sectored cache, 64 byte line size */
+ { 0x67, LVL_1_DATA, 16 }, /* 4-way set assoc, sectored cache, 64 byte line size */
+ { 0x68, LVL_1_DATA, 32 }, /* 4-way set assoc, sectored cache, 64 byte line size */
+ { 0x70, LVL_TRACE, 12 }, /* 8-way set assoc */
+ { 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */
+ { 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */
+ { 0x78, LVL_2, 1024 }, /* 4-way set assoc, 64 byte line size */
+ { 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x7a, LVL_2, 256 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x7b, LVL_2, 512 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x7c, LVL_2, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */
+ { 0x7d, LVL_2, 2048 }, /* 8-way set assoc, 64 byte line size */
+ { 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */
+ { 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */
+ { 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */
+ { 0x84, LVL_2, 1024 }, /* 8-way set assoc, 32 byte line size */
+ { 0x85, LVL_2, 2048 }, /* 8-way set assoc, 32 byte line size */
+ { 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */
+ { 0x87, LVL_2, 1024 }, /* 8-way set assoc, 64 byte line size */
{ 0x00, 0, 0}
};
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
index 423429491f67f..bdd13285fe968 100644
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -44,8 +44,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Intel-defined (#2) */
- "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2",
- "est", NULL, "cid", NULL, NULL, NULL, NULL, NULL,
+ "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est",
+ "tm2", NULL, "cid", NULL, NULL, NULL, "xtpr", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index 6b4a8f3ccbbd7..789af3e9fb1ff 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -13,7 +13,7 @@
static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
-#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000)
+#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000)
static void doublefault_fn(void)
{
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index b0804c01689f4..8bead75aeff1a 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -1739,7 +1739,7 @@ static void __init setup_ioapic_ids_from_mpc(void)
reg_00.raw = io_apic_read(apic, 0);
spin_unlock_irqrestore(&ioapic_lock, flags);
if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)
- panic("could not set ID!\n");
+ printk("could not set ID!\n");
else
apic_printk(APIC_VERBOSE, " ok.\n");
}
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 0b3b83450b19d..346dda408500e 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -183,18 +183,13 @@ void __init select_idle_routine(const struct cpuinfo_x86 *c)
printk("monitor/mwait feature present.\n");
/*
* Skip, if setup has overridden idle.
- * Also, take care of system with asymmetric CPUs.
- * Use, mwait_idle only if all cpus support it.
- * If not, we fallback to default_idle()
+ * One CPU supports mwait => All CPUs supports mwait
*/
if (!pm_idle) {
printk("using mwait in idle threads.\n");
pm_idle = mwait_idle;
}
- return;
}
- pm_idle = default_idle;
- return;
}
static int __init idle_setup (char *str)
@@ -595,7 +590,7 @@ asmlinkage int sys_clone(struct pt_regs regs)
child_tidptr = (int __user *)regs.edi;
if (!newsp)
newsp = regs.esp;
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, parent_tidptr, child_tidptr);
+ return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr);
}
/*
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 57e88b62591d6..019c7a620a1fa 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -411,9 +411,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -492,9 +490,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
@@ -502,11 +498,9 @@ give_sigsegv:
*/
static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
- struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+ sigset_t *oldset, struct pt_regs * regs)
{
- struct k_sigaction *ka = &current->sighand->action[sig-1];
-
/* Are we from a system call? */
if (regs->orig_eax >= 0) {
/* If so, check system call restarting.. */
@@ -534,9 +528,6 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
else
setup_frame(sig, ka, oldset, regs);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -555,6 +546,7 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
{
siginfo_t info;
int signr;
+ struct k_sigaction ka;
/*
* We want the common case to go fast, which
@@ -573,7 +565,7 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!oldset)
oldset = &current->blocked;
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Reenable any watchpoints before delivering the
* signal to user space. The processor register will
@@ -583,7 +575,7 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
__asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7]));
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, oldset, regs);
+ handle_signal(signr, &info, &ka, oldset, regs);
return 1;
}
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index de91beb190ed7..5059818838f62 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -496,16 +496,6 @@ extern struct {
unsigned short ss;
} stack_start;
-static struct task_struct * __init fork_by_hand(void)
-{
- struct pt_regs regs;
- /*
- * don't care about the eip and regs settings since
- * we'll never reschedule the forked task.
- */
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
#ifdef CONFIG_NUMA
/* which logical CPUs are on which nodes */
@@ -801,21 +791,10 @@ static int __init do_boot_cpu(int apicid)
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
- idle = fork_by_hand();
+ idle = fork_idle(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
- wake_up_forked_process(idle);
-
- /*
- * We remove it from the pidhash and the runqueue
- * once we got the process:
- */
- init_idle(idle, cpu);
-
idle->thread.eip = (unsigned long) start_secondary;
-
- unhash_process(idle);
-
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();
@@ -1138,213 +1117,6 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
synchronize_tsc_bp();
}
-#ifdef CONFIG_SCHED_SMT
-#ifdef CONFIG_NUMA
-static struct sched_group sched_group_cpus[NR_CPUS];
-static struct sched_group sched_group_phys[NR_CPUS];
-static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static DEFINE_PER_CPU(struct sched_domain, node_domains);
-__init void arch_init_sched_domains(void)
-{
- int i;
- struct sched_group *first = NULL, *last = NULL;
-
- /* Set up domains */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
- struct sched_domain *node_domain = &per_cpu(node_domains, i);
- int node = cpu_to_node(i);
- cpumask_t nodemask = node_to_cpumask(node);
-
- *cpu_domain = SD_SIBLING_INIT;
- cpu_domain->span = cpu_sibling_map[i];
- cpu_domain->parent = phys_domain;
- cpu_domain->groups = &sched_group_cpus[i];
-
- *phys_domain = SD_CPU_INIT;
- phys_domain->span = nodemask;
- phys_domain->parent = node_domain;
- phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)];
-
- *node_domain = SD_NODE_INIT;
- node_domain->span = cpu_possible_map;
- node_domain->groups = &sched_group_nodes[cpu_to_node(i)];
- }
-
- /* Set up CPU (sibling) groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- int j;
- first = last = NULL;
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- for_each_cpu_mask(j, cpu_domain->span) {
- struct sched_group *cpu = &sched_group_cpus[j];
-
- cpu->cpumask = CPU_MASK_NONE;
- cpu_set(j, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- for (i = 0; i < MAX_NUMNODES; i++) {
- int j;
- cpumask_t nodemask;
- struct sched_group *node = &sched_group_nodes[i];
- cpumask_t node_cpumask = node_to_cpumask(i);
-
- cpus_and(nodemask, node_cpumask, cpu_possible_map);
-
- if (cpus_empty(nodemask))
- continue;
-
- first = last = NULL;
- /* Set up physical groups */
- for_each_cpu_mask(j, nodemask) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, j);
- struct sched_group *cpu = &sched_group_phys[j];
-
- if (j != first_cpu(cpu_domain->span))
- continue;
-
- cpu->cpumask = cpu_domain->span;
- /*
- * Make each extra sibling increase power by 10% of
- * the basic CPU. This is very arbitrary.
- */
- cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
- node->cpu_power += cpu->cpu_power;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- /* Set up nodes */
- first = last = NULL;
- for (i = 0; i < MAX_NUMNODES; i++) {
- struct sched_group *cpu = &sched_group_nodes[i];
- cpumask_t nodemask;
- cpumask_t node_cpumask = node_to_cpumask(i);
-
- cpus_and(nodemask, node_cpumask, cpu_possible_map);
-
- if (cpus_empty(nodemask))
- continue;
-
- cpu->cpumask = nodemask;
- /* ->cpu_power already setup */
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
-
- mb();
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_domain, i);
- }
-}
-#else /* !CONFIG_NUMA */
-static struct sched_group sched_group_cpus[NR_CPUS];
-static struct sched_group sched_group_phys[NR_CPUS];
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-__init void arch_init_sched_domains(void)
-{
- int i;
- struct sched_group *first = NULL, *last = NULL;
-
- /* Set up domains */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
-
- *cpu_domain = SD_SIBLING_INIT;
- cpu_domain->span = cpu_sibling_map[i];
- cpu_domain->parent = phys_domain;
- cpu_domain->groups = &sched_group_cpus[i];
-
- *phys_domain = SD_CPU_INIT;
- phys_domain->span = cpu_possible_map;
- phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)];
- }
-
- /* Set up CPU (sibling) groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- int j;
- first = last = NULL;
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- for_each_cpu_mask(j, cpu_domain->span) {
- struct sched_group *cpu = &sched_group_cpus[j];
-
- cpus_clear(cpu->cpumask);
- cpu_set(j, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- first = last = NULL;
- /* Set up physical groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_group *cpu = &sched_group_phys[i];
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- cpu->cpumask = cpu_domain->span;
- /* See SMT+NUMA setup for comment */
- cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
-
- mb();
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_domain, i);
- }
-}
-#endif /* CONFIG_NUMA */
-#endif /* CONFIG_SCHED_SMT */
-
/* These are wrappers to interface to the new boot process. Someone
who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
void __init smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 829f1c91d813a..8eb5ea15a12b2 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -4,6 +4,7 @@
#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)
@@ -11,7 +12,7 @@ ENTRY(startup_32)
jiffies = jiffies_64;
SECTIONS
{
- . = 0xC0000000 + 0x100000;
+ . = __PAGE_OFFSET + 0x100000;
/* read-only */
_text = .; /* Text and read-only data */
.text : {
@@ -66,9 +67,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/i386/kernel/vsyscall.lds b/arch/i386/kernel/vsyscall.lds.S
index 7ff7f8b9e67b0..a4421421e4001 100644
--- a/arch/i386/kernel/vsyscall.lds
+++ b/arch/i386/kernel/vsyscall.lds.S
@@ -3,9 +3,9 @@
* object prelinked to its virtual address, and with only one read-only
* segment (that fits in one page). This script controls its layout.
*/
+#include <asm/fixmap.h>
-/* This must match <asm/fixmap.h>. */
-VSYSCALL_BASE = 0xffffe000;
+VSYSCALL_BASE = __FIXADDR_TOP - 0x1000;
SECTIONS
{
diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h
index 1cb878fc5b2a7..70691f0c4ce28 100644
--- a/arch/i386/mach-es7000/es7000.h
+++ b/arch/i386/mach-es7000/es7000.h
@@ -29,7 +29,7 @@
#define MIP_BUSY 1
#define MIP_SPIN 0xf0000
-#define MIP_VALID 0x0100000000000000
+#define MIP_VALID 0x0100000000000000ULL
#define MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)
#define MIP_RD_LO(VALUE) (VALUE & 0xffffffff)
diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c
index 784576c53c051..99cfe4bf00331 100644
--- a/arch/i386/mach-es7000/es7000plat.c
+++ b/arch/i386/mach-es7000/es7000plat.c
@@ -237,7 +237,7 @@ es7000_mip_write(struct mip_reg *mip_reg)
}
status = ((unsigned long long)mip_reg->off_0 &
- (unsigned long long)0xffff0000000000) >> 48;
+ (unsigned long long)0xffff0000000000ULL) >> 48;
mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
(unsigned long long)~MIP_VALID);
return status;
diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
index f599d856442d0..25883b44f6253 100644
--- a/arch/i386/mach-generic/bigsmp.c
+++ b/arch/i386/mach-generic/bigsmp.c
@@ -13,15 +13,41 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/dmi.h>
#include <asm/mach-bigsmp/mach_apic.h>
#include <asm/mach-bigsmp/mach_apicdef.h>
#include <asm/mach-bigsmp/mach_ipi.h>
#include <asm/mach-default/mach_mpparse.h>
-int dmi_bigsmp; /* can be set by dmi scanners */
+static int dmi_bigsmp; /* can be set by dmi scanners */
+
+static __init int hp_ht_bigsmp(struct dmi_system_id *d)
+{
+#ifdef CONFIG_X86_GENERICARCH
+ printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
+ dmi_bigsmp = 1;
+#endif
+ return 0;
+}
+
+
+static struct dmi_system_id __initdata bigsmp_dmi_table[] = {
+ { hp_ht_bigsmp, "HP ProLiant DL760 G2", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+ DMI_MATCH(DMI_BIOS_VERSION, "P44-"),
+ }},
+
+ { hp_ht_bigsmp, "HP ProLiant DL740", {
+ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+ DMI_MATCH(DMI_BIOS_VERSION, "P47-"),
+ }},
+ { }
+};
+
static __init int probe_bigsmp(void)
{
+ dmi_check_system(bigsmp_dmi_table);
return dmi_bigsmp;
}
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index ad62185e38a2f..33f7ab3bb58ad 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -523,15 +523,6 @@ start_secondary(void *unused)
return cpu_idle();
}
-static struct task_struct * __init
-fork_by_hand(void)
-{
- struct pt_regs regs;
- /* don't care about the eip and regs settings since we'll
- * never reschedule the forked task. */
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
/* Routine to kick start the given CPU and wait for it to report ready
* (or timeout in startup). When this routine returns, the requested
@@ -587,16 +578,10 @@ do_boot_cpu(__u8 cpu)
hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
cpucount++;
- idle = fork_by_hand();
+ idle = fork_idle(cpu);
if(IS_ERR(idle))
panic("failed fork for CPU%d", cpu);
-
- wake_up_forked_process(idle);
-
- init_idle(idle, cpu);
-
idle->thread.eip = (unsigned long) start_secondary;
- unhash_process(idle);
/* init_tasks (in sched.c) is indexed logically */
stack_start.esp = (void *) idle->thread.esp;
diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile
index 87dd63c9802a7..fc32725068467 100644
--- a/arch/i386/mm/Makefile
+++ b/arch/i386/mm/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux i386-specific parts of the memory manager.
#
-obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o
+obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o mmap.o
obj-$(CONFIG_DISCONTIGMEM) += discontig.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index 2ffc65aacb475..efdcb0da9ffd6 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -417,15 +417,15 @@ void __init zone_sizes_init(void)
* remapped KVA area - mbligh
*/
if (!nid)
- free_area_init_node(nid, NODE_DATA(nid), 0,
- zones_size, start, zholes_size);
+ free_area_init_node(nid, NODE_DATA(nid),
+ zones_size, start, zholes_size);
else {
unsigned long lmem_map;
lmem_map = (unsigned long)node_remap_start_vaddr[nid];
lmem_map += sizeof(pg_data_t) + PAGE_SIZE - 1;
lmem_map &= PAGE_MASK;
- free_area_init_node(nid, NODE_DATA(nid),
- (struct page *)lmem_map, zones_size,
+ NODE_DATA(nid)->node_mem_map = (struct page *)lmem_map;
+ free_area_init_node(nid, NODE_DATA(nid), zones_size,
start, zholes_size);
}
}
diff --git a/arch/i386/mm/mmap.c b/arch/i386/mm/mmap.c
new file mode 100644
index 0000000000000..a6270ee14323a
--- /dev/null
+++ b/arch/i386/mm/mmap.c
@@ -0,0 +1,71 @@
+/*
+ * linux/arch/i386/mm/mmap.c
+ *
+ * flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(struct mm_struct *mm)
+{
+ unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ /*
+ * Fall back to the standard layout if the personality
+ * bit is set, or if the expected stack growth is unlimited:
+ */
+ if (sysctl_legacy_va_layout ||
+ (current->personality & ADDR_COMPAT_LAYOUT) ||
+ current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) {
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base(mm);
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index 2ebc7c6729fce..59ba6f11201f0 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -142,7 +142,7 @@ static void __init pcibios_allocate_resources(int pass)
DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0) {
+ if (!pr || insert_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev));
/* We'll assign a new address later */
r->end -= r->start;
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 381277884e6cb..0fda3d08bb372 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -1055,7 +1055,7 @@ simrs_init (void)
ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
}
- printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",
state->line,
state->port, state->irq,
uart_config[state->type].name);
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index fa3ac962a5f66..d8824113ebaa5 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -41,7 +41,7 @@ ENTRY(ia32_clone)
zxt4 out1=in1 // newsp
mov out3=16 // stacksize (compensates for 16-byte scratch area)
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
- dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK
+ mov out0=in0 // out0 = clone_flags
zxt4 out4=in2 // out4 = parent_tidptr
zxt4 out5=in4 // out5 = child_tidptr
br.call.sptk.many rp=do_fork
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index 793ec3f7682a0..65505630097f3 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -882,9 +882,7 @@ setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs
return 1;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return 0;
}
@@ -952,9 +950,7 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
return 1;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return 0;
}
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index f166571ecbb91..695299af0c603 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -195,11 +195,6 @@ void foo(void)
DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec));
- DEFINE(CLONE_IDLETASK_BIT, 12);
-#if CLONE_IDLETASK != (1 << 12)
-# error "CLONE_IDLETASK_BIT incorrect, please fix"
-#endif
-
DEFINE(CLONE_SETTLS_BIT, 19);
#if CLONE_SETTLS != (1<<19)
# error "CLONE_SETTLS_BIT incorrect, please fix"
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 52576c34c30ac..1fe9575c7f7b5 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -128,7 +128,7 @@ GLOBAL_ENTRY(sys_clone2)
(p6) st8 [r2]=in5 // store TLS in r16 for copy_thread()
mov out5=in4 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
- dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK
+ mov out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork
.ret1: .restore sp
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
@@ -157,7 +157,7 @@ GLOBAL_ENTRY(sys_clone)
(p6) st8 [r2]=in4 // store TLS in r13 (tp)
mov out5=in3 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
- dep out0=0,in0,CLONE_IDLETASK_BIT,1 // out0 = clone_flags & ~CLONE_IDLETASK
+ mov out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork
.ret2: .restore sp
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 5a609295a4e13..db3598d9cf6d3 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -1,7 +1,7 @@
/*
* Architecture-specific signal handling support.
*
- * Copyright (C) 1999-2003 Hewlett-Packard Co
+ * Copyright (C) 1999-2004 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* Derived from i386 and Alpha versions.
@@ -352,13 +352,42 @@ rbs_on_sig_stack (unsigned long bsp)
}
static long
+force_sigsegv_info (int sig, void *addr)
+{
+ unsigned long flags;
+ struct siginfo si;
+
+ if (sig == SIGSEGV) {
+ /*
+ * Acquiring siglock around the sa_handler-update is almost
+ * certainly overkill, but this isn't a
+ * performance-critical path and I'd rather play it safe
+ * here than having to debug a nasty race if and when
+ * something changes in kernel/signal.c that would make it
+ * no longer safe to modify sa_handler without holding the
+ * lock.
+ */
+ spin_lock_irqsave(&current->sighand->siglock, flags);
+ current->sighand->action[sig - 1].sa.sa_handler = SIG_DFL;
+ spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ }
+ si.si_signo = SIGSEGV;
+ si.si_errno = 0;
+ si.si_code = SI_KERNEL;
+ si.si_pid = current->pid;
+ si.si_uid = current->uid;
+ si.si_addr = addr;
+ force_sig_info(SIGSEGV, &si, current);
+ return 0;
+}
+
+static long
setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
struct sigscratch *scr)
{
extern char __kernel_sigtramp[];
unsigned long tramp_addr, new_rbs = 0;
struct sigframe *frame;
- struct siginfo si;
long err;
frame = (void *) scr->pt.r12;
@@ -377,7 +406,7 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return force_sigsegv_info(sig, frame);
err = __put_user(sig, &frame->arg0);
err |= __put_user(&frame->info, &frame->arg1);
@@ -393,8 +422,8 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
err |= __put_user(sas_ss_flags(scr->pt.r12), &frame->sc.sc_stack.ss_flags);
err |= setup_sigcontext(&frame->sc, set, scr);
- if (err)
- goto give_sigsegv;
+ if (unlikely(err))
+ return force_sigsegv_info(sig, frame);
scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */
scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
@@ -422,18 +451,6 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
current->comm, current->pid, sig, scr->pt.r12, frame->sc.sc_ip, frame->handler);
#endif
return 1;
-
- give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- si.si_signo = SIGSEGV;
- si.si_errno = 0;
- si.si_code = SI_KERNEL;
- si.si_pid = current->pid;
- si.si_uid = current->uid;
- si.si_addr = frame;
- force_sig_info(SIGSEGV, &si, current);
- return 0;
}
static long
@@ -449,9 +466,6 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
if (!setup_frame(sig, ka, info, oldset, scr))
return 0;
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
{
@@ -471,7 +485,7 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
long
ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
{
- struct k_sigaction *ka;
+ struct k_sigaction ka;
siginfo_t info;
long restart = in_syscall;
long errno = scr->pt.r8;
@@ -493,7 +507,7 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
* need to push through a forced SIGSEGV.
*/
while (1) {
- int signr = get_signal_to_deliver(&info, &scr->pt, NULL);
+ int signr = get_signal_to_deliver(&info, &ka, &scr->pt, NULL);
/*
* get_signal_to_deliver() may have run a debugger (via notify_parent())
@@ -520,8 +534,6 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
if (signr <= 0)
break;
- ka = &current->sighand->action[signr - 1];
-
if (unlikely(restart)) {
switch (errno) {
case ERESTART_RESTARTBLOCK:
@@ -531,7 +543,7 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
break;
case ERESTARTSYS:
- if ((ka->sa.sa_flags & SA_RESTART) == 0) {
+ if ((ka.sa.sa_flags & SA_RESTART) == 0) {
scr->pt.r8 = ERR_CODE(EINTR);
/* note: scr->pt.r10 is already -1 */
break;
@@ -550,7 +562,7 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
* Whee! Actually deliver the signal. If the delivery failed, we need to
* continue to iterate in this loop so we can deliver the SIGSEGV...
*/
- if (handle_signal(signr, ka, &info, oldset, scr))
+ if (handle_signal(signr, &ka, &info, oldset, scr))
return 1;
}
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 9a0f7923311dc..fb4938347d264 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -356,19 +356,15 @@ start_secondary (void *unused)
return cpu_idle();
}
-static struct task_struct * __devinit
-fork_by_hand (void)
+struct pt_regs * __init idle_regs(struct pt_regs *regs)
{
- /*
- * Don't care about the IP and regs settings since we'll never reschedule the
- * forked task.
- */
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL);
+ return NULL;
}
struct create_idle {
struct task_struct *idle;
struct completion done;
+ int cpu;
};
void
@@ -376,7 +372,7 @@ do_fork_idle(void *_c_idle)
{
struct create_idle *c_idle = _c_idle;
- c_idle->idle = fork_by_hand();
+ c_idle->idle = fork_idle(c_idle->cpu);
complete(&c_idle->done);
}
@@ -384,10 +380,11 @@ static int __devinit
do_boot_cpu (int sapicid, int cpu)
{
int timeout;
- struct create_idle c_idle;
+ struct create_idle c_idle = {
+ .cpu = cpu,
+ .done = COMPLETION_INITIALIZER(c_idle.done),
+ };
DECLARE_WORK(work, do_fork_idle, &c_idle);
-
- init_completion(&c_idle.done);
/*
* We can't use kernel_thread since we must avoid to reschedule the child.
*/
@@ -400,16 +397,6 @@ do_boot_cpu (int sapicid, int cpu)
if (IS_ERR(c_idle.idle))
panic("failed fork for CPU %d", cpu);
- wake_up_forked_process(c_idle.idle);
-
- /*
- * We remove it from the pidhash and the runqueue
- * once we got the process:
- */
- init_idle(c_idle.idle, cpu);
-
- unhash_process(c_idle.idle);
-
task_for_booting_cpu = c_idle.idle;
Dprintk("Sending wakeup vector %lu to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
@@ -719,3 +706,4 @@ init_smp_config(void)
printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n",
ia64_sal_strerror(sal_ret));
}
+
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 57912212b0dd0..5082ca3931844 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -135,12 +135,6 @@ SECTIONS
*(.init.setup)
__setup_end = .;
}
- __param : AT(ADDR(__param) - LOAD_OFFSET)
- {
- __start___param = .;
- *(__param)
- __stop___param = .;
- }
.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET)
{
__initcall_start = .;
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index c0f8f4a3e0198..363ed89d5ddbc 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -267,7 +267,7 @@ paging_init (void)
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0;
- free_area_init_node(0, &contig_page_data, NULL, zones_size, 0,
+ free_area_init_node(0, &contig_page_data, zones_size, 0,
zholes_size);
mem_map = contig_page_data.node_mem_map;
} else {
@@ -280,7 +280,8 @@ paging_init (void)
vmem_map = (struct page *) vmalloc_end;
efi_memmap_walk(create_mem_map_page_table, 0);
- free_area_init_node(0, &contig_page_data, vmem_map, zones_size,
+ contig_page_data.node_mem_map = vmem_map;
+ free_area_init_node(0, &contig_page_data, zones_size,
0, zholes_size);
mem_map = contig_page_data.node_mem_map;
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 23a9490fcfa3c..80b87cc29ab71 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -664,8 +664,7 @@ void paging_init(void)
pfn_offset = mem_data[node].min_pfn;
- free_area_init_node(node, NODE_DATA(node),
- vmem_map + pfn_offset, zones_size,
+ free_area_init_node(node, NODE_DATA(node), zones_size,
pfn_offset, zholes_size);
}
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 3ab0b37e0fa9d..1c4e90c2dc66b 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -429,20 +429,22 @@ virtual_memmap_init (u64 start, u64 end, void *arg)
/ sizeof(struct page));
if (map_start < map_end)
- memmap_init_zone(map_start, (unsigned long) (map_end - map_start),
+ memmap_init_zone((unsigned long)(map_end - map_start),
args->nid, args->zone, page_to_pfn(map_start));
return 0;
}
void
-memmap_init (struct page *start, unsigned long size, int nid,
- unsigned long zone, unsigned long start_pfn)
+memmap_init (unsigned long size, int nid, unsigned long zone,
+ unsigned long start_pfn)
{
if (!vmem_map)
- memmap_init_zone(start, size, nid, zone, start_pfn);
+ memmap_init_zone(size, nid, zone, start_pfn);
else {
+ struct page *start;
struct memmap_init_callback_data args;
+ start = pfn_to_page(start_pfn);
args.start = start;
args.end = start + size;
args.nid = nid;
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index b426ab55ad39e..93b043e2a4359 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -232,7 +232,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
child_tidptr = (int *)regs->d4;
if (!newsp)
newsp = rdusp();
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0,
+ return do_fork(clone_flags, newsp, regs, 0,
parent_tidptr, child_tidptr);
}
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index c37c4dbb8cbee..4a319bdef9572 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -842,9 +842,7 @@ adjust_stack:
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
goto adjust_stack;
}
@@ -925,9 +923,7 @@ adjust_stack:
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
goto adjust_stack;
}
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index b0a5cd53d660b..42aeea9fcb1e0 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -51,9 +51,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index 12931b324a533..7a18ed0621915 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -45,9 +45,6 @@ __init_begin = .;
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
index 581eef2b796b2..b0901d8171d9c 100644
--- a/arch/m68knommu/kernel/process.c
+++ b/arch/m68knommu/kernel/process.c
@@ -188,7 +188,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
newsp = regs->d2;
if (!newsp)
newsp = rdusp();
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL);
+ return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
}
int copy_thread(int nr, unsigned long clone_flags,
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
index 3fb0d78f43b13..0d5891567f03b 100644
--- a/arch/m68knommu/kernel/signal.c
+++ b/arch/m68knommu/kernel/signal.c
@@ -616,9 +616,7 @@ adjust_stack:
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
goto adjust_stack;
}
@@ -685,9 +683,7 @@ adjust_stack:
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
goto adjust_stack;
}
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 4d8f716d76c6f..87f3bc40773f7 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -284,9 +284,6 @@ SECTIONS {
__setup_start = .;
*(.init.setup)
__setup_end = .;
- __start___param = .;
- *(__param)
- __stop___param = .;
__initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index b15f3b0de4741..15ae6af5adf87 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -121,9 +121,7 @@ static void setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs,
return;
segv_and_exit:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
}
static void inline
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index a820be85ecbba..d5a5a46feb9ee 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -406,9 +406,7 @@ static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
return;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
}
#endif
@@ -475,9 +473,7 @@ static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
return;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
}
extern void setup_rt_frame_n32(struct k_sigaction * ka,
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 407beff81d52f..a449a5651c42e 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -574,9 +574,7 @@ static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
return;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
}
static inline void setup_rt_frame(struct k_sigaction * ka,
@@ -647,9 +645,7 @@ static inline void setup_rt_frame(struct k_sigaction * ka,
return;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
}
static inline void handle_signal(unsigned long sig, siginfo_t *info,
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index d262fbdc9d857..d2f8b8cf67e09 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -208,7 +208,5 @@ void setup_rt_frame_n32(struct k_sigaction * ka,
return;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
}
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 1f917fe93f054..61137d771aea1 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -254,16 +254,6 @@ void __devinit smp_prepare_boot_cpu(void)
cpu_set(0, cpu_callin_map);
}
-static struct task_struct * __init fork_by_hand(void)
-{
- struct pt_regs regs;
- /*
- * don't care about the eip and regs settings since
- * we'll never reschedule the forked task.
- */
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
/*
* Startup the CPU with this logical number
*/
@@ -275,20 +265,10 @@ static int __init do_boot_cpu(int cpu)
* The following code is purely to make sure
* Linux can schedule processes on this slave.
*/
- idle = fork_by_hand();
+ idle = fork_idle(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d\n", cpu);
- wake_up_forked_process(idle);
-
- /*
- * We remove it from the pidhash and the runqueue once we've
- * got the process:
- */
- init_idle(idle, cpu);
-
- unhash_process(idle);
-
prom_boot_secondary(cpu, idle);
/* XXXKW timeout */
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 16519f7e8c3ba..51f4676857ed4 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -180,7 +180,7 @@ static_unused int _sys_clone(nabi_no_regargs struct pt_regs regs)
newsp = regs.regs[29];
parent_tidptr = (int *) regs.regs[6];
child_tidptr = (int *) regs.regs[7];
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
+ return do_fork(clone_flags, newsp, &regs, 0,
parent_tidptr, child_tidptr);
}
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 098cfaa23c0e1..beda22006c0a8 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -96,9 +96,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
.early_initcall.init : {
__earlyinitcall_start = .;
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 6c6df7b5b8288..e3cdb958265f0 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -225,7 +225,7 @@ void __init paging_init(void)
pfn_t end_pfn = node_getmaxclick(node) + 1;
zones_size[ZONE_DMA] = end_pfn - start_pfn;
- free_area_init_node(node, NODE_DATA(node), NULL,
+ free_area_init_node(node, NODE_DATA(node),
zones_size, start_pfn, NULL);
if (end_pfn > max_low_pfn)
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
index 6b65bf4683a7d..4abd43910db64 100644
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -7,7 +7,7 @@
* Reference Specification", March 7, 1999, version 0.96. This
* is available at http://parisc-linux.org/documentation/
*
- * Copyright 1999 by Alex deVries <adevries@thepuffingroup.com>
+ * Copyright 1999 by Alex deVries <alex@onefishtwo.ca>
* and copyright 1999 The Puffin Group Inc.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index dd938ef771916..d7365b958f7eb 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -262,7 +262,7 @@ sys_clone(unsigned long clone_flags, unsigned long usp,
if(usp == 0)
usp = regs->gr[30];
- return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, user_tid, NULL);
+ return do_fork(clone_flags, usp, regs, 0, user_tid, NULL);
}
int
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 0f1daa584c9ae..387c26b6ec6aa 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -486,24 +486,6 @@ void __init smp_callin(void)
}
/*
- * Create the idle task for a new Slave CPU. DO NOT use kernel_thread()
- * because that could end up calling schedule(). If it did, the new idle
- * task could get scheduled before we had a chance to remove it from the
- * run-queue...
- */
-static struct task_struct *fork_by_hand(void)
-{
- struct pt_regs regs;
-
- /*
- * don't care about the regs settings since
- * we'll never reschedule the forked task.
- */
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
-
-/*
* Bring one cpu online.
*/
int __init smp_boot_one_cpu(int cpuid)
@@ -521,13 +503,10 @@ int __init smp_boot_one_cpu(int cpuid)
* Sheesh . . .
*/
- idle = fork_by_hand();
if (IS_ERR(idle))
panic("SMP: fork failed for CPU:%d", cpuid);
- wake_up_forked_process(idle);
- init_idle(idle, cpuid);
- unhash_process(idle);
+ idle = fork_idle(cpunum);
idle->thread_info->cpu = cpuid;
/* Let _start know what logical CPU we're booting
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 7da318ed07cfa..f705d4dffde2a 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -130,9 +130,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 871d7df2779c0..065da58079414 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -804,7 +804,7 @@ void __init paging_init(void)
ZONE_DMA zone. */
zones_size[ZONE_DMA] = pmem_ranges[i].pages;
- free_area_init_node(i,NODE_DATA(i),NULL,zones_size,
+ free_area_init_node(i, NODE_DATA(i), zones_size,
pmem_ranges[i].start_pfn, 0);
#ifdef CONFIG_DISCONTIGMEM
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
index 171e5e9001cc1..34a463a94c65a 100644
--- a/arch/ppc/8xx_io/uart.c
+++ b/arch/ppc/8xx_io/uart.c
@@ -2592,7 +2592,7 @@ static int __init rs_8xx_init(void)
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
- printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
+ printk(KERN_INFO "ttyS%d at 0x%04x is a %s\n",
i, (unsigned int)(state->port),
(state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
#ifdef CONFIG_SERIAL_CONSOLE
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 2f019703cb61e..46139ac975638 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -685,7 +685,8 @@ config PPC_OF
config PPC_GEN550
bool
- depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || PRPMC750 || K2 || PRPMC800
+ depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || \
+ PRPMC750 || K2 || PRPMC800 || LOPEC
default y
config FORCE
@@ -811,10 +812,6 @@ config PREEMPT
config HIGHMEM
bool "High memory support"
-config KERNEL_ELF
- bool
- default y
-
source "fs/Kconfig.binfmt"
config PROC_DEVICETREE
@@ -832,10 +829,11 @@ config PREP_RESIDUAL
Some PReP systems have residual data passed to the kernel by the
firmware. This allows detection of memory size, devices present and
other useful pieces of information. Sometimes this information is
- not present or incorrect.
+ not present or incorrect, in which case it could lead to the machine
+ behaving incorrectly. If this happens, either disable PREP_RESIDUAL
+ or pass the 'noresidual' option to the kernel.
- Unless you expect to boot on a PReP system, there is no need to
- select Y.
+ If you are running a PReP system, say Y here, otherwise say N.
config PROC_PREPRESIDUAL
bool "Support for reading of PReP Residual Data in /proc"
diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug
index 7f86f4c8c8cb0..0df2814553d9b 100644
--- a/arch/ppc/Kconfig.debug
+++ b/arch/ppc/Kconfig.debug
@@ -53,6 +53,18 @@ config BDI_SWITCH
Unless you are intending to debug the kernel with one of these
machines, say N here.
+config SCHEDSTATS
+ bool "Collect scheduler statistics"
+ depends on DEBUG_KERNEL && PROC_FS
+ help
+ If you say Y here, additional code will be inserted into the
+ scheduler and related routines to collect statistics about
+ scheduler behavior and provide them in /proc/schedstat. These
+ stats may be useful for both tuning and debugging the scheduler
+ If you aren't debugging the scheduler or trying to tune a specific
+ application, you can say N to avoid the very slight overhead
+ this adds.
+
config BOOTX_TEXT
bool "Support for early boot text console (BootX or OpenFirmware only)"
depends PPC_OF
diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c
index cc93c9eb3caf4..af881d7454ddd 100644
--- a/arch/ppc/amiga/config.c
+++ b/arch/ppc/amiga/config.c
@@ -423,9 +423,6 @@ void __init config_amiga(void)
mach_floppy_setup = amiga_floppy_setup;
#endif
mach_reset = amiga_reset;
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
#ifdef CONFIG_HEARTBEAT
mach_heartbeat = amiga_heartbeat;
#endif
diff --git a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c
index 58e2a92e8d5f3..cd2573d95b034 100644
--- a/arch/ppc/boot/simple/misc-embedded.c
+++ b/arch/ppc/boot/simple/misc-embedded.c
@@ -72,6 +72,14 @@ extern void flush_instruction_cache(void);
extern void gunzip(void *, int, unsigned char *, int *);
extern void embed_config(bd_t **bp);
+/* Weak function for boards which don't need to build the
+ * board info struct because they are using PPCBoot/U-Boot.
+ */
+void __attribute__ ((weak))
+embed_config(bd_t **bdp)
+{
+}
+
unsigned long
load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
{
diff --git a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig
index 6e1a38d72b308..0785159d6ae0b 100644
--- a/arch/ppc/configs/mvme5100_defconfig
+++ b/arch/ppc/configs/mvme5100_defconfig
@@ -4,23 +4,39 @@
CONFIG_MMU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
# Loadable module support
@@ -33,24 +49,26 @@ CONFIG_OBSOLETE_MODPARM=y
CONFIG_KMOD=y
#
-# Platform support
+# Processor
#
-CONFIG_PPC=y
-CONFIG_PPC32=y
CONFIG_6xx=y
# CONFIG_40x is not set
+# CONFIG_44x is not set
# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
# CONFIG_8xx is not set
+# CONFIG_E500 is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_STD_MMU=y
#
-# IBM 4xx options
+# Platform options
#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
# CONFIG_PPC_MULTIPLATFORM is not set
# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
+# CONFIG_WILLOW is not set
# CONFIG_PCORE is not set
# CONFIG_POWERPMC250 is not set
# CONFIG_EV64260 is not set
@@ -66,34 +84,31 @@ CONFIG_MVME5100=y
# CONFIG_K2 is not set
# CONFIG_PAL4 is not set
# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_LITE5200 is not set
# CONFIG_MVME5100_IPMC761_PRESENT is not set
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
-CONFIG_ALTIVEC=y
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
#
-# General setup
+# Bus options
#
-# CONFIG_HIGHMEM is not set
+CONFIG_GENERIC_ISA_DMA=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
# CONFIG_PCI_LEGACY_PROC is not set
# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
#
# Advanced setup
@@ -110,14 +125,28 @@ CONFIG_TASK_SIZE=0x80000000
CONFIG_BOOT_LOAD=0x00800000
#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+
+#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
# Plug and Play support
#
-# CONFIG_PNP is not set
#
# Block devices
@@ -129,46 +158,46 @@ CONFIG_BOOT_LOAD=0x00800000
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
#
# IDE chipset support/bugfixes
#
+CONFIG_IDE_GENERIC=y
# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
#
-# SCSI support
+# SCSI device support
#
CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
@@ -184,64 +213,69 @@ CONFIG_BLK_DEV_SR=y
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_REPORT_LUNS is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
#
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
# SCSI low-level drivers
#
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
-# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=32
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
# Fusion MPT device support
#
# CONFIG_FUSION is not set
#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
#
# CONFIG_IEEE1394 is not set
@@ -251,6 +285,10 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_I2O is not set
#
+# Macintosh device drivers
+#
+
+#
# Networking support
#
CONFIG_NET=y
@@ -261,28 +299,33 @@ CONFIG_NET=y
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
# IP: Netfilter Configuration
#
CONFIG_IP_NF_CONNTRACK=m
@@ -293,11 +336,13 @@ CONFIG_IP_NF_IRC=m
# CONFIG_IP_NF_QUEUE is not set
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_LIMIT=m
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
CONFIG_IP_NF_MATCH_MAC=m
CONFIG_IP_NF_MATCH_PKTTYPE=m
CONFIG_IP_NF_MATCH_MARK=m
CONFIG_IP_NF_MATCH_MULTIPORT=m
CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_DSCP=m
CONFIG_IP_NF_MATCH_AH_ESP=m
@@ -307,15 +352,15 @@ CONFIG_IP_NF_MATCH_TCPMSS=m
CONFIG_IP_NF_MATCH_HELPER=m
CONFIG_IP_NF_MATCH_STATE=m
CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
CONFIG_IP_NF_MATCH_OWNER=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
CONFIG_IP_NF_NAT=m
CONFIG_IP_NF_NAT_NEEDED=y
CONFIG_IP_NF_TARGET_MASQUERADE=m
CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
# CONFIG_IP_NF_NAT_LOCAL is not set
# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
CONFIG_IP_NF_NAT_IRC=m
@@ -326,21 +371,24 @@ CONFIG_IP_NF_TARGET_ULOG=m
CONFIG_IP_NF_TARGET_TCPMSS=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
+# CONFIG_IP_NF_ARP_MANGLE is not set
CONFIG_IP_NF_COMPAT_IPCHAINS=m
# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
-CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
@@ -352,29 +400,33 @@ CONFIG_IPV6_SCTP__=y
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
-# CONFIG_OAKNET is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
@@ -389,10 +441,11 @@ CONFIG_NET_PCI=y
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PIO is not set
-# CONFIG_E100 is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_E100_NAPI is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
@@ -403,6 +456,7 @@ CONFIG_EEPRO100=y
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
#
# Ethernet (1000 Mbit)
@@ -421,80 +475,91 @@ CONFIG_EEPRO100=y
# Ethernet (10000 Mbit)
#
# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_S2IO is not set
#
-# Wireless LAN (non-hamradio)
+# Token Ring devices
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
#
-# Token Ring devices (depends on LLC=y)
+# Wireless LAN (non-hamradio)
#
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
#
# ISDN subsystem
#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
#
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
#
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
#
# Input device support
#
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
#
# Userland interfaces
#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
#
# Input Device Drivers
#
-
-#
-# Macintosh device drivers
-#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
#
# Character devices
#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -502,6 +567,7 @@ CONFIG_SOUND_GAMEPORT=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
@@ -510,26 +576,8 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_QIC02_TAPE is not set
#
@@ -551,11 +599,23 @@ CONFIG_GEN_RTC=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Misc devices
+#
#
# Multimedia devices
@@ -568,6 +628,33 @@ CONFIG_GEN_RTC=y
# CONFIG_DVB is not set
#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -592,17 +679,20 @@ CONFIG_EXT2_FS=y
#
# DOS/FAT/NT Filesystems
#
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
@@ -611,6 +701,7 @@ CONFIG_RAMFS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
@@ -625,19 +716,20 @@ CONFIG_RAMFS=y
# Network File Systems
#
CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
# 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_EXPORTFS is not set
CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
@@ -647,31 +739,26 @@ CONFIG_SUNRPC=y
CONFIG_MSDOS_PARTITION=y
#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
+# Native Language Support
#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
+# CONFIG_NLS is not set
#
-# Bluetooth support
+# Library routines
#
-# CONFIG_BT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
#
-# Library routines
+# Profiling support
#
-# CONFIG_CRC32 is not set
+# CONFIG_PROFILING is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
#
# Security options
diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S
index ee0705c6e3abc..6ba5ef411dd0a 100644
--- a/arch/ppc/kernel/cpu_setup_6xx.S
+++ b/arch/ppc/kernel/cpu_setup_6xx.S
@@ -218,10 +218,10 @@ setup_745x_specifics:
/* All of the bits we have to set.....
*/
- ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_LRSTK
+ ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_LRSTK | HID0_BTIC
BEGIN_FTR_SECTION
- ori r11,r11,HID0_BTIC
-END_FTR_SECTION_IFCLR(CPU_FTR_NO_BTIC)
+ xori r11,r11,HID0_BTIC
+END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC)
BEGIN_FTR_SECTION
oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */
END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
index b60fa998bbced..b3d3d371a25ac 100644
--- a/arch/ppc/kernel/cputable.c
+++ b/arch/ppc/kernel/cputable.c
@@ -55,7 +55,7 @@ extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spe
#endif
/* We need to mark all pages as being coherent if we're SMP or we
- * have a 754x and an MPC107 host bridge.
+ * have a 74[45]x and an MPC107 host bridge.
*/
#if defined(CONFIG_SMP) || defined(CONFIG_MPC10X_BRIDGE)
#define CPU_FTR_COMMON CPU_FTR_NEED_COHERENT
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index 5adb6be19bef5..6db80f60c1aea 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -21,6 +21,7 @@
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
+#include <linux/sysctl.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -65,3 +66,36 @@ int cpu_idle(void)
default_idle();
return 0;
}
+
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
+/*
+ * Register the sysctl to set/clear powersave_nap.
+ */
+extern unsigned long powersave_nap;
+
+static ctl_table powersave_nap_ctl_table[]={
+ {
+ .ctl_name = KERN_PPC_POWERSAVE_NAP,
+ .procname = "powersave-nap",
+ .data = &powersave_nap,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { 0, },
+};
+static ctl_table powersave_nap_sysctl_root[] = {
+ { 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, },
+ { 0,},
+};
+
+static int __init
+register_powersave_nap_sysctl(void)
+{
+ register_sysctl_table(powersave_nap_sysctl_root, 0);
+
+ return 0;
+}
+
+__initcall(register_powersave_nap_sysctl);
+#endif
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 873199e435f66..26ff1a34af8d2 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -617,10 +617,9 @@ _GLOBAL(flush_instruction_cache)
* flush_icache_range(unsigned long start, unsigned long stop)
*/
_GLOBAL(flush_icache_range)
- mfspr r5,PVR
- rlwinm r5,r5,16,16,31
- cmpi 0,r5,1
- beqlr /* for 601, do nothing */
+BEGIN_FTR_SECTION
+ blr /* for 601, do nothing */
+END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
li r5,L1_CACHE_LINE_SIZE-1
andc r3,r3,r5
subf r4,r3,r4
@@ -735,10 +734,9 @@ _GLOBAL(flush_dcache_all)
* void __flush_dcache_icache(void *page)
*/
_GLOBAL(__flush_dcache_icache)
- mfspr r5,PVR
- rlwinm r5,r5,16,16,31
- cmpi 0,r5,1
- beqlr /* for 601, do nothing */
+BEGIN_FTR_SECTION
+ blr /* for 601, do nothing */
+END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
rlwinm r3,r3,0,0,19 /* Get page base address */
li r4,4096/L1_CACHE_LINE_SIZE /* Number of lines in a page */
mtctr r4
@@ -764,10 +762,9 @@ _GLOBAL(__flush_dcache_icache)
* void __flush_dcache_icache_phys(unsigned long physaddr)
*/
_GLOBAL(__flush_dcache_icache_phys)
- mfspr r5,PVR
- rlwinm r5,r5,16,16,31
- cmpi 0,r5,1
- beqlr /* for 601, do nothing */
+BEGIN_FTR_SECTION
+ blr /* for 601, do nothing */
+END_FTR_SECTION_IFSET(PPC_FEATURE_UNIFIED_CACHE)
mfmsr r10
rlwinm r0,r10,0,28,26 /* clear DR */
mtmsr r0
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 089be143690e4..ca212f9496a88 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -144,8 +144,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
-void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
{
unsigned long offset = 0;
@@ -158,6 +157,7 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
region->start = res->start - offset;
region->end = res->end - offset;
}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
/*
* We need to avoid collisions with `mirrored' VGA ports
@@ -172,8 +172,7 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
* but we want to try to avoid allocating at 0x2900-0x2bff
* which might have be mirrored at 0x0100-0x03ff..
*/
-void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
unsigned long align)
{
struct pci_dev *dev = data;
@@ -193,7 +192,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size,
}
}
}
-
+EXPORT_SYMBOL(pcibios_align_resource);
/*
* Handle resources of PCI devices. If the world were perfect, we could
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 91592c03ea8bb..d8e027fd48494 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -20,6 +20,7 @@
#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/seq_file.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -34,9 +35,6 @@
static int ppc_htab_show(struct seq_file *m, void *v);
static ssize_t ppc_htab_write(struct file * file, const char __user * buffer,
size_t count, loff_t *ppos);
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos);
-
extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern unsigned long _SDR1;
@@ -438,3 +436,32 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
*ppos += *lenp;
return 0;
}
+
+#ifdef CONFIG_SYSCTL
+/*
+ * Register our sysctl.
+ */
+static ctl_table htab_ctl_table[]={
+ {
+ .ctl_name = KERN_PPC_L2CR,
+ .procname = "l2cr",
+ .mode = 0644,
+ .proc_handler = &proc_dol2crvec,
+ },
+ { 0, },
+};
+static ctl_table htab_sysctl_root[] = {
+ { 1, "kernel", NULL, 0, 0755, htab_ctl_table, },
+ { 0,},
+};
+
+static int __init
+register_ppc_htab_sysctl(void)
+{
+ register_sysctl_table(htab_sysctl_root, 0);
+
+ return 0;
+}
+
+__initcall(register_ppc_htab_sysctl);
+#endif
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 2ea505381139c..cc20fa3e61a9e 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -555,8 +555,7 @@ int sys_clone(unsigned long clone_flags, unsigned long usp,
CHECK_FULL_REGS(regs);
if (usp == 0)
usp = regs->gpr[1]; /* stack pointer for child */
- return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0,
- parent_tidp, child_tidp);
+ return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp);
}
int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 092035ae1a12d..9b0e077fe846b 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -747,6 +747,10 @@ void __init setup_arch(char **cmdline_p)
if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
#endif
+#ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+#endif
+
ppc_md.setup_arch();
if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 20b6446c060df..ac2673ca5133a 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -404,9 +404,7 @@ badframe:
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig)
@@ -556,9 +554,7 @@ badframe:
printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
@@ -604,7 +600,7 @@ badframe:
int do_signal(sigset_t *oldset, struct pt_regs *regs)
{
siginfo_t info;
- struct k_sigaction *ka;
+ struct k_sigaction ka;
unsigned long frame, newsp;
int signr, ret;
@@ -613,9 +609,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
newsp = frame = 0;
- signr = get_signal_to_deliver(&info, regs, NULL);
-
- ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (TRAP(regs) == 0x0C00 /* System Call! */
&& regs->ccr & 0x10000000 /* error signalled */
@@ -626,7 +620,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (signr > 0
&& (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
|| (ret == ERESTARTSYS
- && !(ka->sa.sa_flags & SA_RESTART)))) {
+ && !(ka.sa.sa_flags & SA_RESTART)))) {
/* make the system call return an EINTR error */
regs->result = -EINTR;
regs->gpr[3] = EINTR;
@@ -645,7 +639,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (signr == 0)
return 0; /* no signals delivered */
- if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+ if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
&& !on_sig_stack(regs->gpr[1]))
newsp = current->sas_ss_sp + current->sas_ss_size;
else
@@ -653,17 +647,14 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
newsp &= ~0xfUL;
/* Whee! Actually deliver the signal. */
- if (ka->sa.sa_flags & SA_SIGINFO)
- handle_rt_signal(signr, ka, &info, oldset, regs, newsp);
+ if (ka.sa.sa_flags & SA_SIGINFO)
+ handle_rt_signal(signr, &ka, &info, oldset, regs, newsp);
else
- handle_signal(signr, ka, &info, oldset, regs, newsp);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
+ handle_signal(signr, &ka, &info, oldset, regs, newsp);
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ if (!(ka.sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigorsets(&current->blocked,&current->blocked,&ka.sa.sa_mask);
sigaddset(&current->blocked, signr);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index c28fbf398391c..d3ffa353d29a3 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -364,22 +364,15 @@ int __devinit start_secondary(void *unused)
int __cpu_up(unsigned int cpu)
{
- struct pt_regs regs;
struct task_struct *p;
char buf[32];
int c;
/* create a process for the processor */
/* only regs.msr is actually used, and 0 is OK for it */
- memset(&regs, 0, sizeof(struct pt_regs));
- p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+ p = fork_idle(cpu);
if (IS_ERR(p))
panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
- wake_up_forked_process(p);
-
- init_idle(p, cpu);
- unhash_process(p);
-
secondary_ti = p->thread_info;
p->thread_info->cpu = cpu;
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
index 342848fe56568..66e513a4f9724 100644
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -102,9 +102,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/ppc/math-emu/op-common.h b/arch/ppc/math-emu/op-common.h
index aeaa1cde5d73f..afb82b6498ce8 100644
--- a/arch/ppc/math-emu/op-common.h
+++ b/arch/ppc/math-emu/op-common.h
@@ -82,7 +82,6 @@ do { \
if (X##_e <= _FP_WFRACBITS_##fs) \
{ \
_FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \
- __ret |= _FP_ROUND(wc, X); \
_FP_FRAC_SLL_##wc(X, 1); \
if (_FP_FRAC_OVERP_##wc(fs, X)) \
{ \
diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
index 6c9bde47360e2..5d2a41bd0a8a5 100644
--- a/arch/ppc/platforms/4xx/ebony.c
+++ b/arch/ppc/platforms/4xx/ebony.c
@@ -361,10 +361,6 @@ ebony_setup_arch(void)
ROOT_DEV = Root_HDA1;
#endif
-#ifdef CONFIG_VT
- conswitchp = &dummy_con;
-#endif
-
ebony_early_serial_map();
ibm4xxPIC_InitSenses = ebony_IRQ_initsenses;
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
index 6376890e36c92..69aa01119e206 100644
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -319,10 +319,6 @@ ocotea_setup_arch(void)
ROOT_DEV = Root_HDA1;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
ocotea_early_serial_map(&clocks);
/* Identify the system */
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
index aada7e4561b58..686dd6d9a1bbf 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -120,10 +120,6 @@ mpc8540ads_setup_arch(void)
mpc85xx_setup_hose();
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
#ifdef CONFIG_SERIAL_8250
mpc85xx_early_serial_map();
#endif
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index c7e53e39c6806..2d04ee93f7aa3 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -358,10 +358,6 @@ mpc85xx_cds_setup_arch(void)
mpc85xx_setup_hose();
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
#ifdef CONFIG_SERIAL_8250
mpc85xx_early_serial_map();
#endif
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
index a4a91aa6afce0..50cc50a0c2bb7 100644
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -144,9 +144,6 @@ sbc8560_setup_arch(void)
/* setup PCI host bridges */
mpc85xx_setup_hose();
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
#ifdef CONFIG_SERIAL_8250
sbc8560_early_serial_map();
#endif
diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
index c59d4871d9509..c393f58e5a969 100644
--- a/arch/ppc/platforms/Makefile
+++ b/arch/ppc/platforms/Makefile
@@ -21,23 +21,21 @@ endif
obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o
obj-$(CONFIG_PREP_RESIDUAL) += residual.o
obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o
-obj-$(CONFIG_EST8260) += est8260_setup.o
-obj-$(CONFIG_PQ2ADS) += pq2ads_setup.o
+obj-$(CONFIG_PQ2ADS) += pq2ads.o
obj-$(CONFIG_TQM8260) += tqm8260_setup.o
obj-$(CONFIG_EV64260) += ev64260_setup.o
obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o
obj-$(CONFIG_K2) += k2.o
-obj-$(CONFIG_LOPEC) += lopec_setup.o lopec_pci.o
+obj-$(CONFIG_LOPEC) += lopec.o
obj-$(CONFIG_MCPN765) += mcpn765.o
obj-$(CONFIG_MENF1) += menf1_setup.o menf1_pci.o
-obj-$(CONFIG_MVME5100) += mvme5100_setup.o mvme5100_pci.o
+obj-$(CONFIG_MVME5100) += mvme5100.o
obj-$(CONFIG_PAL4) += pal4_setup.o pal4_pci.o
obj-$(CONFIG_PCORE) += pcore.o
obj-$(CONFIG_POWERPMC250) += powerpmc250.o
obj-$(CONFIG_PPLUS) += pplus.o
obj-$(CONFIG_PRPMC750) += prpmc750.o
obj-$(CONFIG_PRPMC800) += prpmc800.o
-obj-$(CONFIG_RPX8260) += rpx8260.o
obj-$(CONFIG_SANDPOINT) += sandpoint.o
obj-$(CONFIG_SBC82xx) += sbc82xx.o
obj-$(CONFIG_SPRUCE) += spruce.o
diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
index 56be78eb45c6b..a811eddd4e150 100644
--- a/arch/ppc/platforms/chrp_setup.c
+++ b/arch/ppc/platforms/chrp_setup.c
@@ -250,13 +250,6 @@ chrp_setup_arch(void)
*/
sio_init();
- /*
- * Setup the console operations
- */
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
/* Get the event scan rate for the rtas so we know how
* often it expects a heartbeat. -- Cort
*/
diff --git a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h
index bc51f072a2b97..adba68ecf57bf 100644
--- a/arch/ppc/platforms/est8260.h
+++ b/arch/ppc/platforms/est8260.h
@@ -10,6 +10,9 @@
#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "EST Corporation"
+#define CPUINFO_MACHINE "SBC8260 PowerPC"
/* A Board Information structure that is given to a program when
* prom starts it up.
diff --git a/arch/ppc/platforms/est8260_setup.c b/arch/ppc/platforms/est8260_setup.c
deleted file mode 100644
index ecd114fb42e7a..0000000000000
--- a/arch/ppc/platforms/est8260_setup.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * arch/ppc/platforms/est8260_setup.c
- *
- * EST8260 platform support
- *
- * Author: Allen Curtis <acurtis@onz.com>
- * Derived from: m8260_setup.c by Dan Malek, MVista
- *
- * Copyright 2002 Ones and Zeros, 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.
- */
-
-#include <linux/config.h>
-#include <linux/seq_file.h>
-
-#include <asm/mpc8260.h>
-#include <asm/machdep.h>
-
-static void (*callback_setup_arch)(void);
-
-extern unsigned char __res[sizeof(bd_t)];
-
-extern void m8260_init(unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, unsigned long r7);
-
-static int
-est8260_show_cpuinfo(struct seq_file *m)
-{
- bd_t *binfo = (bd_t *)__res;
-
- seq_printf(m, "vendor\t\t: EST Corporation\n"
- "machine\t\t: SBC8260 PowerPC\n"
- "\n"
- "mem size\t\t: 0x%08x\n"
- "console baud\t\t: %d\n"
- "\n",
- binfo->bi_memsize,
- binfo->bi_baudrate);
- return 0;
-}
-
-static void __init
-est8260_setup_arch(void)
-{
- printk("EST SBC8260 Port\n");
- callback_setup_arch();
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- /* Generic 8260 platform initialization */
- m8260_init(r3, r4, r5, r6, r7);
-
- /* Anything special for this platform */
- ppc_md.show_cpuinfo = est8260_show_cpuinfo;
-
- callback_setup_arch = ppc_md.setup_arch;
- ppc_md.setup_arch = est8260_setup_arch;
-}
diff --git a/arch/ppc/platforms/k2.c b/arch/ppc/platforms/k2.c
index 4e2e18a528501..8a602039f428d 100644
--- a/arch/ppc/platforms/k2.c
+++ b/arch/ppc/platforms/k2.c
@@ -464,10 +464,6 @@ static void __init k2_setup_arch(void)
ROOT_DEV = Root_HDC1;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
/* Identify the system */
printk(KERN_INFO "System Identification: SBS K2 - PowerPC 750 @ "
"%d Mhz\n", k2_get_cpu_speed() / 1000000);
diff --git a/arch/ppc/platforms/lopec_setup.c b/arch/ppc/platforms/lopec.c
index 8e98f260759bc..0037f5ca46f47 100644
--- a/arch/ppc/platforms/lopec_setup.c
+++ b/arch/ppc/platforms/lopec.c
@@ -1,12 +1,12 @@
/*
- * arch/ppc/platforms/lopec_setup.c
+ * arch/ppc/platforms/lopec.c
*
* Setup routines for the Motorola LoPEC.
*
* Author: Dan Cox
- * danc@mvista.com
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
*
- * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
@@ -23,7 +23,10 @@
#include <linux/initrd.h>
#include <linux/console.h>
#include <linux/root_dev.h>
+#include <linux/pci.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
#include <asm/io.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
@@ -32,8 +35,7 @@
#include <asm/mpc10x.h>
#include <asm/hw_irq.h>
#include <asm/prep_nvram.h>
-
-extern void lopec_find_bridges(void);
+#include <asm/kgdb.h>
/*
* Define all of the IRQ senses and polarities. Taken from the
@@ -58,6 +60,83 @@ static u_char lopec_openpic_initsenses[16] __initdata = {
(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* IRQ 15 */
};
+static inline int __init
+lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ int irq;
+ static char pci_irq_table[][4] = {
+ {16, 0, 0, 0}, /* ID 11 - Winbond */
+ {22, 0, 0, 0}, /* ID 12 - SCSI */
+ {0, 0, 0, 0}, /* ID 13 - nothing */
+ {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */
+ {27, 0, 0, 0}, /* ID 15 - USB */
+ {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */
+ {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */
+ {25, 0, 0, 0}, /* ID 18 - PCI slot */
+ {0, 0, 0, 0}, /* ID 19 - nothing */
+ {0, 0, 0, 0}, /* ID 20 - nothing */
+ {0, 0, 0, 0}, /* ID 21 - nothing */
+ {0, 0, 0, 0}, /* ID 22 - nothing */
+ {0, 0, 0, 0}, /* ID 23 - nothing */
+ {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */
+ {0, 0, 0, 0}, /* ID 25 - nothing */
+ {0, 0, 0, 0} /* ID 26 - PMC Slot 2b */
+ };
+ const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4;
+
+ irq = PCI_IRQ_TABLE_LOOKUP;
+ if (!irq)
+ return 0;
+
+ return irq;
+}
+
+static void __init
+lopec_setup_winbond_83553(struct pci_controller *hose)
+{
+ int devfn;
+
+ devfn = PCI_DEVFN(11,0);
+
+ /* IDE interrupt routing (primary 14, secondary 15) */
+ early_write_config_byte(hose, 0, devfn, 0x43, 0xef);
+ /* PCI interrupt routing */
+ early_write_config_word(hose, 0, devfn, 0x44, 0x0000);
+
+ /* ISA-PCI address decoder */
+ early_write_config_byte(hose, 0, devfn, 0x48, 0xf0);
+
+ /* RTC, kb, not used in PPC */
+ early_write_config_byte(hose, 0, devfn, 0x4d, 0x00);
+ early_write_config_byte(hose, 0, devfn, 0x4e, 0x04);
+ devfn = PCI_DEVFN(11, 1);
+ early_write_config_byte(hose, 0, devfn, 0x09, 0x8f);
+ early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011);
+}
+
+static void __init
+lopec_find_bridges(void)
+{
+ struct pci_controller *hose;
+
+ hose = pcibios_alloc_controller();
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ if (mpc10x_bridge_init(hose, MPC10X_MEM_MAP_B, MPC10X_MEM_MAP_B,
+ MPC10X_MAPB_EUMB_BASE) == 0) {
+
+ hose->mem_resources[0].end = 0xffffffff;
+ lopec_setup_winbond_83553(hose);
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = lopec_map_irq;
+ }
+}
+
static int
lopec_show_cpuinfo(struct seq_file *m)
{
@@ -154,18 +233,16 @@ lopec_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data,
uint alt_status_base;
int i;
- for(i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
hw->io_ports[i] = reg++;
if (data == lopec_ide_regbase[0]) {
alt_status_base = lopec_ide_ctl_regbase[0] + 2;
hw->irq = 14;
- }
- else if (data == lopec_ide_regbase[1]) {
+ } else if (data == lopec_ide_regbase[1]) {
alt_status_base = lopec_ide_ctl_regbase[1] + 2;
hw->irq = 15;
- }
- else {
+ } else {
alt_status_base = 0;
hw->irq = 0;
}
@@ -234,60 +311,18 @@ lopec_map_io(void)
io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO);
}
-static void __init
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
lopec_set_bat(void)
{
- unsigned long batu, batl;
-
- __asm__ __volatile__(
- "lis %0,0xf800\n \
- ori %1,%0,0x002a\n \
- ori %0,%0,0x0ffe\n \
- mtspr 0x21e,%0\n \
- mtspr 0x21f,%1\n \
- isync\n \
- sync "
- : "=r" (batu), "=r" (batl));
+ mb();
+ mtspr(DBAT1U, 0xf8000ffe);
+ mtspr(DBAT1L, 0xf800002a);
+ mb();
}
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
- SERIAL_PORT_DFNS /* Defined in <asm/serial.h> */
-};
-
-volatile unsigned char *com_port;
-volatile unsigned char *com_port_lsr;
-
-static void
-serial_writechar(char c)
-{
- while ((*com_port_lsr & UART_LSR_THRE) == 0)
- ;
- *com_port = c;
-}
-
-void
-lopec_progress(char *s, unsigned short hex)
-{
- volatile char c;
-
- com_port = (volatile unsigned char *) rs_table[0].port;
- com_port_lsr = com_port + UART_LSR;
-
- while ((c = *s++) != 0)
- serial_writechar(c);
-
- /* Most messages don't have a newline in them */
- serial_writechar('\n');
- serial_writechar('\r');
-}
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-
TODC_ALLOC();
static void __init
@@ -307,15 +342,12 @@ lopec_setup_arch(void)
else
#elif defined(CONFIG_ROOT_NFS)
ROOT_DEV = Root_NFS;
-#elif defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#elif defined(CONFIG_BLK_DEV_IDEDISK)
ROOT_DEV = Root_HDA1;
#else
ROOT_DEV = Root_SDA1;
#endif
-#ifdef CONFIG_VT
- conswitchp = &dummy_con;
-#endif
#ifdef CONFIG_PPCBUG_NVRAM
/* Read in NVRAM data */
init_prep_nvram();
@@ -373,6 +405,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports;
#endif
#ifdef CONFIG_SERIAL_TEXT_DEBUG
- ppc_md.progress = lopec_progress;
+ ppc_md.progress = gen550_progress;
#endif
}
diff --git a/arch/ppc/platforms/lopec_serial.h b/arch/ppc/platforms/lopec.h
index 5490edb2d2636..5490edb2d2636 100644
--- a/arch/ppc/platforms/lopec_serial.h
+++ b/arch/ppc/platforms/lopec.h
diff --git a/arch/ppc/platforms/lopec_pci.c b/arch/ppc/platforms/lopec_pci.c
deleted file mode 100644
index 11aab4d632c8d..0000000000000
--- a/arch/ppc/platforms/lopec_pci.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * arch/ppc/platforms/lopec_pci.c
- *
- * PCI setup routines for the Motorola LoPEC.
- *
- * Author: Dan Cox
- * danc@mvista.com (or, alternately, source@mvista.com)
- *
- * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/mpc10x.h>
-
-static inline int __init
-lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
- int irq;
- static char pci_irq_table[][4] = {
- {16, 0, 0, 0}, /* ID 11 - Winbond */
- {22, 0, 0, 0}, /* ID 12 - SCSI */
- {0, 0, 0, 0}, /* ID 13 - nothing */
- {17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */
- {27, 0, 0, 0}, /* ID 15 - USB */
- {23, 0, 0, 0}, /* ID 16 - PMC slot 1 */
- {24, 0, 0, 0}, /* ID 17 - PMC slot 2 */
- {25, 0, 0, 0}, /* ID 18 - PCI slot */
- {0, 0, 0, 0}, /* ID 19 - nothing */
- {0, 0, 0, 0}, /* ID 20 - nothing */
- {0, 0, 0, 0}, /* ID 21 - nothing */
- {0, 0, 0, 0}, /* ID 22 - nothing */
- {0, 0, 0, 0}, /* ID 23 - nothing */
- {0, 0, 0, 0}, /* ID 24 - PMC slot 1b */
- {0, 0, 0, 0}, /* ID 25 - nothing */
- {0, 0, 0, 0} /* ID 26 - PMC Slot 2b */
- };
- const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4;
-
- irq = PCI_IRQ_TABLE_LOOKUP;
- if (!irq)
- return 0;
-
- return irq;
-}
-
-void __init
-lopec_setup_winbond_83553(struct pci_controller *hose)
-{
- int devfn;
-
- devfn = PCI_DEVFN(11,0);
-
- /* IDE interrupt routing (primary 14, secondary 15) */
- early_write_config_byte(hose, 0, devfn, 0x43, 0xef);
- /* PCI interrupt routing */
- early_write_config_word(hose, 0, devfn, 0x44, 0x0000);
-
- /* ISA-PCI address decoder */
- early_write_config_byte(hose, 0, devfn, 0x48, 0xf0);
-
- /* RTC, kb, not used in PPC */
- early_write_config_byte(hose, 0, devfn, 0x4d, 0x00);
- early_write_config_byte(hose, 0, devfn, 0x4e, 0x04);
- devfn = PCI_DEVFN(11, 1);
- early_write_config_byte(hose, 0, devfn, 0x09, 0x8f);
- early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011);
-}
-
-void __init
-lopec_find_bridges(void)
-{
- struct pci_controller *hose;
-
- hose = pcibios_alloc_controller();
- if (!hose)
- return;
-
- hose->first_busno = 0;
- hose->last_busno = 0xff;
-
- if (mpc10x_bridge_init(hose,
- MPC10X_MEM_MAP_B,
- MPC10X_MEM_MAP_B,
- MPC10X_MAPB_EUMB_BASE) == 0) {
-
- hose->mem_resources[0].end = 0xffffffff;
- lopec_setup_winbond_83553(hose);
- hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
- ppc_md.pci_swizzle = common_swizzle;
- ppc_md.pci_map_irq = lopec_map_irq;
- }
-}
diff --git a/arch/ppc/platforms/mcpn765.c b/arch/ppc/platforms/mcpn765.c
index 06ed9384fdd06..348118b75dae7 100644
--- a/arch/ppc/platforms/mcpn765.c
+++ b/arch/ppc/platforms/mcpn765.c
@@ -58,8 +58,6 @@
#include <asm/kgdb.h>
#include "mcpn765.h"
-#include "mcpn765_serial.h"
-
static u_char mcpn765_openpic_initsenses[] __initdata = {
(IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE),/* 16: i8259 cascade */
@@ -324,10 +322,6 @@ mcpn765_setup_arch(void)
ROOT_DEV = Root_SDA2;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
if ( ppc_md.progress )
ppc_md.progress("mcpn765_setup_arch: find_bridges", 0);
diff --git a/arch/ppc/platforms/mcpn765.h b/arch/ppc/platforms/mcpn765.h
index 87233831763e0..4d35ecad097b0 100644
--- a/arch/ppc/platforms/mcpn765.h
+++ b/arch/ppc/platforms/mcpn765.h
@@ -6,7 +6,7 @@
* Author: Mark A. Greer
* mgreer@mvista.com
*
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
@@ -25,6 +25,7 @@
#ifndef __PPC_PLATFORMS_MCPN765_H
#define __PPC_PLATFORMS_MCPN765_H
+#include <linux/config.h>
/* PCI Memory space mapping info */
#define MCPN765_PCI_MEM_SIZE 0x40000000U
@@ -65,14 +66,57 @@
#define MCPN765_BOARD_EXT_FEATURE_REG 0xfef880f0U
#define MCPN765_BOARD_LAST_RESET_REG 0xfef880f8U
-/* UART base addresses are defined in <asm-ppc/platforms/mcpn765_serial.h> */
+/* Defines for UART */
+
+/* Define the UART base addresses */
+#define MCPN765_SERIAL_1 0xfef88000
+#define MCPN765_SERIAL_2 0xfef88200
+#define MCPN765_SERIAL_3 0xfef88400
+#define MCPN765_SERIAL_4 0xfef88600
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE 64
+#else
+#define RS_TABLE_SIZE 4
+#endif
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD ( 1843200 / 16 )
+#define UART_CLK 1843200
+
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#endif
+
+/* All UART IRQ's are wire-OR'd to IRQ 17 */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_1, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_2, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_3, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\
+ iomem_base: (u8 *)MCPN765_SERIAL_4, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
/* Define the NVRAM/RTC address strobe & data registers */
#define MCPN765_PHYS_NVRAM_AS0 0xfef880c8U
#define MCPN765_PHYS_NVRAM_AS1 0xfef880d0U
#define MCPN765_PHYS_NVRAM_DATA 0xfef880d8U
-
extern void mcpn765_find_bridges(void);
#endif /* __PPC_PLATFORMS_MCPN765_H */
diff --git a/arch/ppc/platforms/mcpn765_serial.h b/arch/ppc/platforms/mcpn765_serial.h
deleted file mode 100644
index 312467234847c..0000000000000
--- a/arch/ppc/platforms/mcpn765_serial.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * include/asm-ppc/mcpn765_serial.h
- *
- * Definitions for Motorola MCG MCPN765 cPCI board support
- *
- * Author: Mark A. Greer
- * mgreer@mvista.com
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __ASMPPC_MCPN765_SERIAL_H
-#define __ASMPPC_MCPN765_SERIAL_H
-
-#include <linux/config.h>
-
-/* Define the UART base addresses */
-#define MCPN765_SERIAL_1 0xfef88000
-#define MCPN765_SERIAL_2 0xfef88200
-#define MCPN765_SERIAL_3 0xfef88400
-#define MCPN765_SERIAL_4 0xfef88600
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE 4
-#endif
-
-/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
-#define BASE_BAUD ( 1843200 / 16 )
-#define UART_CLK 1843200
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-/* All UART IRQ's are wire-OR'd to IRQ 17 */
-#define STD_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, MCPN765_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */\
- iomem_base: (u8 *)MCPN765_SERIAL_1, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MCPN765_SERIAL_2, 17, STD_COM_FLAGS, /* ttyS1 */\
- iomem_base: (u8 *)MCPN765_SERIAL_2, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MCPN765_SERIAL_3, 17, STD_COM_FLAGS, /* ttyS2 */\
- iomem_base: (u8 *)MCPN765_SERIAL_3, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MCPN765_SERIAL_4, 17, STD_COM_FLAGS, /* ttyS3 */\
- iomem_base: (u8 *)MCPN765_SERIAL_4, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM },
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DFNS
-
-#endif /* __ASMPPC_MCPN765_SERIAL_H */
diff --git a/arch/ppc/platforms/mvme5100_setup.c b/arch/ppc/platforms/mvme5100.c
index bc9c9f46a9f6b..b08be24589972 100644
--- a/arch/ppc/platforms/mvme5100_setup.c
+++ b/arch/ppc/platforms/mvme5100.c
@@ -1,11 +1,11 @@
/*
- * arch/ppc/platforms/mvme5100_setup.c
+ * arch/ppc/platforms/mvme5100.c
*
* Board setup routines for the Motorola MVME5100.
*
* Author: Matt Porter <mporter@mvista.com>
*
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
@@ -16,56 +16,142 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/reboot.h>
#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
#include <linux/initrd.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/ide.h>
#include <linux/seq_file.h>
+#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <asm/time.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
-#include <platforms/mvme5100.h>
#include <asm/todc.h>
#include <asm/pci-bridge.h>
#include <asm/bootinfo.h>
-#include <asm/pplus.h>
-
-extern char cmd_line[];
-
-static u_char mvme5100_openpic_initsenses[] __initdata = {
- 0, /* 16: i8259 cascade (active high) */
- 1, /* 17: TL16C550 UART 1,2 */
- 1, /* 18: Enet 1 (front panel or P2) */
- 1, /* 19: Hawk Watchdog 1,2 */
- 1, /* 20: DS1621 thermal alarm */
- 1, /* 21: Universe II LINT0# */
- 1, /* 22: Universe II LINT1# */
- 1, /* 23: Universe II LINT2# */
- 1, /* 24: Universe II LINT3# */
- 1, /* 25: PMC1 INTA#, PMC2 INTB# */
- 1, /* 26: PMC1 INTB#, PMC2 INTC# */
- 1, /* 27: PMC1 INTC#, PMC2 INTD# */
- 1, /* 28: PMC1 INTD#, PMC2 INTA# */
- 1, /* 29: Enet 2 (front panel) */
- 1, /* 30: Abort Switch */
- 1, /* 31: RTC Alarm */
+#include <asm/hawk.h>
+
+#include <platforms/pplus.h>
+#include <platforms/mvme5100.h>
+
+static u_char mvme5100_openpic_initsenses[16] __initdata = {
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* i8259 cascade */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* TL16C550 UART 1,2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet1 front panel or P2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Hawk Watchdog 1,2 */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* DS1621 thermal alarm */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT0# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT1# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT2# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Universe II LINT3# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTA#, PMC2 INTB# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTB#, PMC2 INTC# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTC#, PMC2 INTD# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* PMC1 INTD#, PMC2 INTA# */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Enet 2 (front panel) */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* Abort Switch */
+ (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* RTC Alarm */
};
+static inline int
+mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+ int irq;
+
+ static char pci_irq_table[][4] =
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {
+ { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */
+ { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
+ { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */
+ { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */
+ { 0, 0, 0, 0 }, /* IDSEL 15 - unused */
+ { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */
+ { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */
+ { 0, 0, 0, 0 }, /* IDSEL 18 - unused */
+ { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */
+ { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */
+ };
+
+ const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
+ irq = PCI_IRQ_TABLE_LOOKUP;
+ /* If lookup is zero, always return 0 */
+ if (!irq)
+ return 0;
+ else
+#ifdef CONFIG_MVME5100_IPMC761_PRESENT
+ /* If IPMC761 present, return table value */
+ return irq;
+#else
+ /* If IPMC761 not present, we don't have an i8259 so adjust */
+ return (irq - NUM_8259_INTERRUPTS);
+#endif
+}
+
+static void
+mvme5100_pcibios_fixup_resources(struct pci_dev *dev)
+{
+ int i;
+
+ if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+ (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK))
+ for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
+ {
+ dev->resource[i].start = 0;
+ dev->resource[i].end = 0;
+ }
+}
+
+static void __init
+mvme5100_setup_bridge(void)
+{
+ struct pci_controller* hose;
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+ hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET;
+
+ pci_init_resource(&hose->io_resource, MVME5100_PCI_LOWER_IO,
+ MVME5100_PCI_UPPER_IO, IORESOURCE_IO,
+ "PCI host bridge");
+
+ pci_init_resource(&hose->mem_resources[0], MVME5100_PCI_LOWER_MEM,
+ MVME5100_PCI_UPPER_MEM, IORESOURCE_MEM,
+ "PCI host bridge");
+
+ hose->io_space.start = MVME5100_PCI_LOWER_IO;
+ hose->io_space.end = MVME5100_PCI_UPPER_IO;
+ hose->mem_space.start = MVME5100_PCI_LOWER_MEM;
+ hose->mem_space.end = MVME5100_PCI_UPPER_MEM;
+ hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE;
+
+ /* Use indirect method of Hawk */
+ setup_indirect_pci(hose, MVME5100_PCI_CONFIG_ADDR,
+ MVME5100_PCI_CONFIG_DATA);
+
+ hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+ ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources;
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_map_irq = mvme5100_map_irq;
+}
+
static void __init
mvme5100_setup_arch(void)
{
@@ -85,10 +171,6 @@ mvme5100_setup_arch(void)
ROOT_DEV = Root_SDA2;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
if ( ppc_md.progress )
ppc_md.progress("mvme5100_setup_arch: find_bridges", 0);
@@ -96,7 +178,7 @@ mvme5100_setup_arch(void)
mvme5100_setup_bridge();
/* Find and map our OpenPIC */
- pplus_mpic_init(MVME5100_PCI_MEM_OFFSET);
+ hawk_mpic_init(MVME5100_PCI_MEM_OFFSET);
OpenPIC_InitSenses = mvme5100_openpic_initsenses;
OpenPIC_NumInitSenses = sizeof(mvme5100_openpic_initsenses);
@@ -136,16 +218,19 @@ mvme5100_init_IRQ(void)
if ( ppc_md.progress )
ppc_md.progress("init_irq: enter", 0);
+ openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000);
#ifdef CONFIG_MVME5100_IPMC761_PRESENT
- openpic_init(1, NUM_8259_INTERRUPTS, NULL, -1);
- openpic_hookup_cascade(NUM_8259_INTERRUPTS,"82c59 cascade",&i8259_irq);
+ openpic_init(NUM_8259_INTERRUPTS);
+ openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+ &i8259_irq);
- for(i=0; i < NUM_8259_INTERRUPTS; i++)
+ /* Map i8259 interrupts. */
+ for (i = 0; i < NUM_8259_INTERRUPTS; i++)
irq_desc[i].handler = &i8259_pic;
i8259_init(NULL);
#else
- openpic_init(1, 0, NULL, -1);
+ openpic_init(0);
#endif
if ( ppc_md.progress )
@@ -160,32 +245,16 @@ mvme5100_init_IRQ(void)
static __inline__ void
mvme5100_set_bat(void)
{
- unsigned long bat3u, bat3l;
- static int mapping_set = 0;
-
- if (!mapping_set) {
-
- __asm__ __volatile__(
- " lis %0,0xf000\n \
- ori %1,%0,0x002a\n \
- ori %0,%0,0x1ffe\n \
- mtspr 0x21e,%0\n \
- mtspr 0x21f,%1\n \
- isync\n \
- sync "
- : "=r" (bat3u), "=r" (bat3l));
-
- mapping_set = 1;
- }
-
- return;
+ mb();
+ mtspr(DBAT1U, 0xf0001ffe);
+ mtspr(DBAT1L, 0xf000002a);
+ mb();
}
static unsigned long __init
mvme5100_find_end_of_memory(void)
{
- mvme5100_set_bat();
- return pplus_get_mem_size(MVME5100_HAWK_SMC_BASE);
+ return hawk_get_mem_size(MVME5100_HAWK_SMC_BASE);
}
static void __init
@@ -248,6 +317,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
parse_bootinfo(find_bootinfo());
+ mvme5100_set_bat();
isa_io_base = MVME5100_ISA_IO_BASE;
isa_mem_base = MVME5100_ISA_MEM_BASE;
@@ -266,11 +336,8 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.find_end_of_memory = mvme5100_find_end_of_memory;
ppc_md.setup_io_mappings = mvme5100_map_io;
- TODC_INIT(TODC_TYPE_MK48T37,
- MVME5100_NVRAM_AS0,
- MVME5100_NVRAM_AS1,
- MVME5100_NVRAM_DATA,
- 8);
+ TODC_INIT(TODC_TYPE_MK48T37, MVME5100_NVRAM_AS0, MVME5100_NVRAM_AS1,
+ MVME5100_NVRAM_DATA, 8);
ppc_md.time_init = todc_time_init;
ppc_md.set_rtc_time = todc_set_rtc_time;
@@ -279,6 +346,4 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.nvram_read_val = todc_m48txx_read_val;
ppc_md.nvram_write_val = todc_m48txx_write_val;
-
- ppc_md.progress = NULL;
}
diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h
index 5cc61d18b3b4d..edd479439a4e4 100644
--- a/arch/ppc/platforms/mvme5100.h
+++ b/arch/ppc/platforms/mvme5100.h
@@ -63,10 +63,29 @@
#define MVME5100_SERIAL_IRQ 1
#endif
-#define MVME5100_WINBOND_DEVFN 0x58
-#define MVME5100_WINBOND_VIDDID 0x056510ad
+#define RS_TABLE_SIZE 4
-extern void mvme5100_setup_bridge(void);
+#define BASE_BAUD ( MVME5100_BASE_BAUD / 16 )
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+/* All UART IRQ's are wire-OR'd to one MPIC IRQ */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, MVME5100_SERIAL_1, \
+ MVME5100_SERIAL_IRQ, \
+ STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (unsigned char *)MVME5100_SERIAL_1, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM }, \
+ { 0, BASE_BAUD, MVME5100_SERIAL_2, \
+ MVME5100_SERIAL_IRQ, \
+ STD_COM_FLAGS, /* ttyS1 */ \
+ iomem_base: (unsigned char *)MVME5100_SERIAL_2, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
#endif /* __ASM_MVME5100_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/mvme5100_pci.c b/arch/ppc/platforms/mvme5100_pci.c
deleted file mode 100644
index 0675ab6902ffa..0000000000000
--- a/arch/ppc/platforms/mvme5100_pci.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * arch/ppc/platforms/mvme5100_pci.c
- *
- * PCI setup routines for the Motorola MVME5100.
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <platforms/mvme5100.h>
-#include <asm/pplus.h>
-
-static inline int
-mvme5100_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
- int irq;
-
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- { 0, 0, 0, 0 }, /* IDSEL 11 - Winbond */
- { 0, 0, 0, 0 }, /* IDSEL 12 - unused */
- { 21, 22, 23, 24 }, /* IDSEL 13 - Universe II */
- { 18, 0, 0, 0 }, /* IDSEL 14 - Enet 1 */
- { 0, 0, 0, 0 }, /* IDSEL 15 - unused */
- { 25, 26, 27, 28 }, /* IDSEL 16 - PMC Slot 1 */
- { 28, 25, 26, 27 }, /* IDSEL 17 - PMC Slot 2 */
- { 0, 0, 0, 0 }, /* IDSEL 18 - unused */
- { 29, 0, 0, 0 }, /* IDSEL 19 - Enet 2 */
- { 0, 0, 0, 0 }, /* IDSEL 20 - PMCSPAN */
- };
-
- const long min_idsel = 11, max_idsel = 20, irqs_per_slot = 4;
- irq = PCI_IRQ_TABLE_LOOKUP;
- /* If lookup is zero, always return 0 */
- if (!irq)
- return 0;
- else
-#ifdef CONFIG_MVME5100_IPMC761_PRESENT
- /* If IPMC761 present, return table value */
- return irq;
-#else
- /* If IPMC761 not present, we don't have an i8259 so adjust */
- return (irq - NUM_8259_INTERRUPTS);
-#endif
-}
-
-static void
-mvme5100_pcibios_fixup_resources(struct pci_dev *dev)
-{
- int i;
-
- if ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
- (dev->device == PCI_DEVICE_ID_MOTOROLA_HAWK))
- for (i=0; i<DEVICE_COUNT_RESOURCE; i++)
- {
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- }
-}
-
-void __init
-mvme5100_setup_bridge(void)
-{
- struct pci_controller* hose;
-
- hose = pcibios_alloc_controller();
-
- if (!hose)
- return;
-
- hose->first_busno = 0;
- hose->last_busno = 0xff;
- hose->pci_mem_offset = MVME5100_PCI_MEM_OFFSET;
-
- pci_init_resource(&hose->io_resource,
- MVME5100_PCI_LOWER_IO,
- MVME5100_PCI_UPPER_IO,
- IORESOURCE_IO,
- "PCI host bridge");
-
- pci_init_resource(&hose->mem_resources[0],
- MVME5100_PCI_LOWER_MEM,
- MVME5100_PCI_UPPER_MEM,
- IORESOURCE_MEM,
- "PCI host bridge");
-
- hose->io_space.start = MVME5100_PCI_LOWER_IO;
- hose->io_space.end = MVME5100_PCI_UPPER_IO;
- hose->mem_space.start = MVME5100_PCI_LOWER_MEM;
- hose->mem_space.end = MVME5100_PCI_UPPER_MEM;
- hose->io_base_virt = (void *)MVME5100_ISA_IO_BASE;
-
- /* Use indirect method of Hawk */
- setup_indirect_pci(hose,
- MVME5100_PCI_CONFIG_ADDR,
- MVME5100_PCI_CONFIG_DATA);
-
- hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
- ppc_md.pcibios_fixup_resources = mvme5100_pcibios_fixup_resources;
- ppc_md.pci_swizzle = common_swizzle;
- ppc_md.pci_map_irq = mvme5100_map_irq;
-}
diff --git a/arch/ppc/platforms/mvme5100_serial.h b/arch/ppc/platforms/mvme5100_serial.h
deleted file mode 100644
index 7fb34ec625836..0000000000000
--- a/arch/ppc/platforms/mvme5100_serial.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * include/asm-ppc/mvme5100_serial.h
- *
- * Definitions for Motorola MVME5100 support
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_MVME5100_SERIAL_H__
-#define __ASM_MVME5100_SERIAL_H__
-
-#include <linux/config.h>
-#include <platforms/mvme5100.h>
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE 4
-#endif
-
-#define BASE_BAUD ( MVME5100_BASE_BAUD / 16 )
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-/* All UART IRQ's are wire-OR'd to one MPIC IRQ */
-#define STD_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, MVME5100_SERIAL_1, \
- MVME5100_SERIAL_IRQ, \
- STD_COM_FLAGS, /* ttyS0 */ \
- iomem_base: (unsigned char *)MVME5100_SERIAL_1, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM }, \
- { 0, BASE_BAUD, MVME5100_SERIAL_2, \
- MVME5100_SERIAL_IRQ, \
- STD_COM_FLAGS, /* ttyS1 */ \
- iomem_base: (unsigned char *)MVME5100_SERIAL_2, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM },
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DFNS
-
-#endif /* __ASM_MVME5100_SERIAL_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/pcore.c b/arch/ppc/platforms/pcore.c
index 9c428720dab3a..da022ecd861f6 100644
--- a/arch/ppc/platforms/pcore.c
+++ b/arch/ppc/platforms/pcore.c
@@ -228,10 +228,6 @@ pcore_setup_arch(void)
ROOT_DEV = Root_SDA2;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
printk(KERN_INFO "Force PowerCore ");
if (board_type == PCORE_TYPE_6750)
printk("6750\n");
diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
index b05cee1f7216c..79fc295143ebd 100644
--- a/arch/ppc/platforms/pmac_setup.c
+++ b/arch/ppc/platforms/pmac_setup.c
@@ -318,9 +318,6 @@ pmac_setup_arch(void)
#ifdef CONFIG_NVRAM
pmac_nvram_init();
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
ROOT_DEV = Root_RAM0;
diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h
index b834e17868dc2..41a6dc8819115 100644
--- a/arch/ppc/platforms/powerpmc250.h
+++ b/arch/ppc/platforms/powerpmc250.h
@@ -7,7 +7,7 @@
*
* Borrowed heavily from prpmc750.h by Matt Porter <mporter@mvista.com>
*
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
@@ -16,8 +16,6 @@
#ifndef __ASMPPC_POWERPMC250_H
#define __ASMPPC_POWERPMC250_H
-#include <linux/serial_reg.h>
-
#define POWERPMC250_PCI_CONFIG_ADDR 0x80000cf8
#define POWERPMC250_PCI_CONFIG_DATA 0x80000cfc
@@ -37,4 +35,18 @@
#define POWERPMC250_SERIAL 0xff000000
#define POWERPMC250_SERIAL_IRQ 20
+/* UART Defines. */
+#define RS_TABLE_SIZE 1
+
+#define BASE_BAUD (POWERPMC250_BASE_BAUD / 16)
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+#define SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, POWERPMC250_SERIAL, POWERPMC250_SERIAL_IRQ, \
+ STD_COM_FLAGS, /* ttyS0 */ \
+ iomem_base: (u8 *)POWERPMC250_SERIAL, \
+ iomem_reg_shift: 0, \
+ io_type: SERIAL_IO_MEM }
+
#endif /* __ASMPPC_POWERPMC250_H */
diff --git a/arch/ppc/platforms/powerpmc250_serial.h b/arch/ppc/platforms/powerpmc250_serial.h
deleted file mode 100644
index 0a9e28a5529d3..0000000000000
--- a/arch/ppc/platforms/powerpmc250_serial.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * include/asm-ppc/platforms/powerpmc250_serial.h
- *
- * Motorola PrPMC750 serial support
- *
- * Author: Troy Benjegerdes <tbenjegerdes@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASMPPC_POWERPMC250_SERIAL_H
-#define __ASMPPC_POWERPMC250_SERIAL_H
-
-#include <linux/config.h>
-#include <platforms/powerpmc250.h>
-
-#define RS_TABLE_SIZE 1
-
-#define BASE_BAUD (POWERPMC250_BASE_BAUD / 16)
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
-#endif
-
-#define SERIAL_PORT_DFNS \
-{ 0, BASE_BAUD, POWERPMC250_SERIAL, POWERPMC250_SERIAL_IRQ, STD_COM_FLAGS, /* ttyS0 */\
- iomem_base: (u8 *)POWERPMC250_SERIAL, \
- iomem_reg_shift: 0, \
- io_type: SERIAL_IO_MEM }
-
-#endif
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c
index 673641ff4bf53..7922346f1a3f3 100644
--- a/arch/ppc/platforms/pplus.c
+++ b/arch/ppc/platforms/pplus.c
@@ -583,8 +583,6 @@ static void __init pplus_setup_arch(void)
vgacon_remap_base = (unsigned long)ioremap(PPLUS_ISA_MEM_BASE,
0x08000000);
conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
- conswitchp = &dummy_con;
#endif
#ifdef CONFIG_PPCBUG_NVRAM
/* Read in NVRAM data */
diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c
new file mode 100644
index 0000000000000..cecaba630565f
--- /dev/null
+++ b/arch/ppc/platforms/pq2ads.c
@@ -0,0 +1,26 @@
+/*
+ * arch/ppc/platforms/pq2ads.c
+ *
+ * PQ2ADS platform support
+ *
+ * Author: Kumar Gala <kumar.gala@freescale.com>
+ * Derived from: est8260_setup.c by Allen Curtis
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+
+#include <asm/mpc8260.h>
+
+void __init
+m82xx_board_init(void)
+{
+ /* Enable the 2nd UART port */
+ *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2;
+}
diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h
index 1bee6ca56e46e..0c17a0cda3a19 100644
--- a/arch/ppc/platforms/pq2ads.h
+++ b/arch/ppc/platforms/pq2ads.h
@@ -23,6 +23,10 @@
#define BOOTROM_RESTART_ADDR ((uint)0xff000104)
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Motorola"
+#define CPUINFO_MACHINE "PQ2 ADS PowerPC"
+
/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
* only on word boundaries.
* Not all are used (yet), or are interesting to us (yet).
diff --git a/arch/ppc/platforms/pq2ads_setup.c b/arch/ppc/platforms/pq2ads_setup.c
deleted file mode 100644
index eaeb2d9640df3..0000000000000
--- a/arch/ppc/platforms/pq2ads_setup.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * arch/ppc/platforms/pq2ads_setup.c
- *
- * PQ2ADS platform support
- *
- * Author: Kumar Gala <kumar.gala@freescale.com>
- * Derived from: est8260_setup.c by Allen Curtis
- *
- * 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.
- */
-
-#include <linux/config.h>
-#include <linux/seq_file.h>
-
-#include <asm/mpc8260.h>
-#include <asm/machdep.h>
-
-static void (*callback_setup_arch)(void);
-
-extern unsigned char __res[sizeof(bd_t)];
-
-extern void m8260_init(unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, unsigned long r7);
-
-static int
-pq2ads_show_cpuinfo(struct seq_file *m)
-{
- bd_t *binfo = (bd_t *)__res;
-
- seq_printf(m, "vendor\t\t: Motorola\n"
- "machine\t\t: PQ2 ADS PowerPC\n"
- "\n"
- "mem size\t\t: 0x%08lx\n"
- "console baud\t\t: %ld\n"
- "\n",
- binfo->bi_memsize,
- binfo->bi_baudrate);
- return 0;
-}
-
-static void __init
-pq2ads_setup_arch(void)
-{
- printk("PQ2 ADS Port\n");
- callback_setup_arch();
- *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_RS232_EN2;
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- /* Generic 8260 platform initialization */
- m8260_init(r3, r4, r5, r6, r7);
-
- /* Anything special for this platform */
- ppc_md.show_cpuinfo = pq2ads_show_cpuinfo;
-
- callback_setup_arch = ppc_md.setup_arch;
- ppc_md.setup_arch = pq2ads_setup_arch;
-}
diff --git a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
index 58775fc7f8cc8..a528562ccf168 100644
--- a/arch/ppc/platforms/prep_pci.c
+++ b/arch/ppc/platforms/prep_pci.c
@@ -836,52 +836,59 @@ struct mot_info {
void __init
ibm_prep_init(void)
{
-#ifdef CONFIG_PREP_RESIDUAL
- u32 addr, real_addr, len;
- PPC_DEVICE *mpic;
- PnP_TAG_PACKET *pkt;
-
- /* Use the PReP residual data to determine if an OpenPIC is
- * present. If so, get the large vendor packet which will
- * tell us the base address and length in memory.
- * If we are successful, ioremap the memory area and set
- * OpenPIC_Addr (this indicates that the OpenPIC was found).
- */
- mpic = residual_find_device(-1, NULL, SystemPeripheral,
- ProgrammableInterruptController, MPIC, 0);
- if (!mpic)
- return;
+ if (have_residual_data) {
+ u32 addr, real_addr, len, offset;
+ PPC_DEVICE *mpic;
+ PnP_TAG_PACKET *pkt;
+
+ /* Use the PReP residual data to determine if an OpenPIC is
+ * present. If so, get the large vendor packet which will
+ * tell us the base address and length in memory.
+ * If we are successful, ioremap the memory area and set
+ * OpenPIC_Addr (this indicates that the OpenPIC was found).
+ */
+ mpic = residual_find_device(-1, NULL, SystemPeripheral,
+ ProgrammableInterruptController, MPIC, 0);
+ if (!mpic)
+ return;
- pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
- mpic->AllocatedOffset, 9, 0);
+ pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+ mpic->AllocatedOffset, 9, 0);
- if (!pkt)
- return;
+ if (!pkt)
+ return;
#define p pkt->L4_Pack.L4_Data.L4_PPCPack
- if (!((p.PPCData[0] == 2) && (p.PPCData[1] == 32)))
- return; /* not a 32-bit memory address */
+ if (p.PPCData[1] == 32) {
+ switch (p.PPCData[0]) {
+ case 1: offset = PREP_ISA_IO_BASE; break;
+ case 2: offset = PREP_ISA_MEM_BASE; break;
+ default: return; /* Not I/O or memory?? */
+ }
+ }
+ else
+ return; /* Not a 32-bit address */
- real_addr = ld_le32((unsigned int *) (p.PPCData + 4));
- if (real_addr == 0xffffffff)
- return;
+ real_addr = ld_le32((unsigned int *) (p.PPCData + 4));
+ if (real_addr == 0xffffffff)
+ return;
- /* Adjust address to be as seen by CPU */
- addr = real_addr + PREP_ISA_MEM_BASE;
+ /* Adjust address to be as seen by CPU */
+ addr = real_addr + offset;
- len = ld_le32((unsigned int *) (p.PPCData + 12));
- if (!len)
- return;
+ len = ld_le32((unsigned int *) (p.PPCData + 12));
+ if (!len)
+ return;
#undef p
- OpenPIC_Addr = ioremap(addr, len);
- ppc_md.get_irq = openpic_get_irq;
+ OpenPIC_Addr = ioremap(addr, len);
+ ppc_md.get_irq = openpic_get_irq;
- OpenPIC_InitSenses = prep_openpic_initsenses;
- OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
+ OpenPIC_InitSenses = prep_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
- printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x "
- "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr);
-#endif
+ printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x "
+ "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr);
+ }
}
static void __init
@@ -901,6 +908,17 @@ ibm43p_pci_map_non0(struct pci_dev *dev)
}
void __init
+prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ if (have_residual_data) {
+ Motherboard_map_name = res->VitalProductData.PrintableModel;
+ Motherboard_map = NULL;
+ Motherboard_routes = NULL;
+ residual_irq_mask(irq_edge_mask_lo, irq_edge_mask_hi);
+ }
+}
+
+void __init
prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
{
Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
@@ -1011,21 +1029,31 @@ prep_route_pci_interrupts(void)
}
} else if ( _prep_type == _PREP_IBM ) {
unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
+ unsigned short irq_edge_mask;
+ int i;
setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi);
outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */
outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */
+
+ irq_edge_mask = (irq_edge_mask_hi << 8) | irq_edge_mask_lo;
+ for (i = 0; i < 16; ++i, irq_edge_mask >>= 1)
+ if (irq_edge_mask & 1)
+ irq_desc[i].status |= IRQ_LEVEL;
} else {
printk("No known machine pci routing!\n");
return;
}
/* Set up mapping from slots */
- for (i = 1; i <= 4; i++)
- ibc_pirq[i-1] = Motherboard_routes[i];
- /* Enable PCI interrupts */
- *ibc_pcicon |= 0x20;
+ if (Motherboard_routes) {
+ for (i = 1; i <= 4; i++)
+ ibc_pirq[i-1] = Motherboard_routes[i];
+
+ /* Enable PCI interrupts */
+ *ibc_pcicon |= 0x20;
+ }
}
void __init
@@ -1171,38 +1199,52 @@ void __init
prep_pcibios_fixup(void)
{
struct pci_dev *dev = NULL;
+ int irq;
+ int have_openpic = (OpenPIC_Addr != NULL);
prep_route_pci_interrupts();
printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
- if (OpenPIC_Addr) {
- /* PCI interrupts are controlled by the OpenPIC */
- while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- if (dev->bus->number == 0) {
- dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- } else {
- if (Motherboard_non0 != NULL)
- Motherboard_non0(dev);
- }
- }
-
- /* Setup the Winbond or Via PIB */
- prep_pib_init();
-
- return;
- }
- dev = NULL;
+ /* Iterate through all the PCI devices, setting the IRQ */
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
/*
- * Use our old hard-coded kludge to figure out what
- * irq this device uses. This is necessary on things
- * without residual data. -- Cort
+ * If we have residual data, then this is easy: query the
+ * residual data for the IRQ line allocated to the device.
+ * This works the same whether we have an OpenPic or not.
+ */
+ if (have_residual_data) {
+ irq = residual_pcidev_irq(dev);
+ dev->irq = have_openpic ? openpic_to_irq(irq) : irq;
+ }
+ /*
+ * If we don't have residual data, then we need to use
+ * tables to determine the IRQ. The table organisation
+ * is different depending on whether there is an OpenPIC
+ * or not. The tables are only used for bus 0, so check
+ * this first.
*/
- unsigned char d = PCI_SLOT(dev->devfn);
- dev->irq = Motherboard_routes[Motherboard_map[d]];
+ else if (dev->bus->number == 0) {
+ irq = Motherboard_map[PCI_SLOT(dev->devfn)];
+ dev->irq = have_openpic ? openpic_to_irq(irq)
+ : Motherboard_routes[irq];
+ }
+ /*
+ * Finally, if we don't have residual data and the bus is
+ * non-zero, use the callback (if provided)
+ */
+ else {
+ if (Motherboard_non0 != NULL)
+ Motherboard_non0(dev);
+
+ continue;
+ }
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
+
+ /* Setup the Winbond or Via PIB */
+ prep_pib_init();
}
static void __init
@@ -1262,14 +1304,15 @@ prep_find_bridges(void)
PREP_ISA_IO_BASE + 0xcfc);
printk("PReP architecture\n");
-#ifdef CONFIG_PREP_RESIDUAL
- {
+
+ if (have_residual_data) {
PPC_DEVICE *hostbridge;
hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
BridgeController, PCIBridge, -1, 0);
if (hostbridge &&
- hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+ ((hostbridge->DeviceId.Interface == PCIBridgeIndirect) ||
+ (hostbridge->DeviceId.Interface == PCIBridgeRS6K))) {
PnP_TAG_PACKET * pkt;
pkt = PnP_find_large_vendor_packet(
res->DevicePnPHeap+hostbridge->AllocatedOffset,
@@ -1284,7 +1327,6 @@ prep_find_bridges(void)
setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
}
}
-#endif /* CONFIG_PREP_RESIDUAL */
ppc_md.pcibios_fixup = prep_pcibios_fixup;
ppc_md.pcibios_after_init = prep_pcibios_after_init;
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 99acd5170e8fe..8051df176f654 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -79,6 +79,7 @@ extern void prep_find_bridges(void);
int _prep_type;
+extern void prep_residual_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
@@ -193,9 +194,8 @@ prep_ibm_cpuinfo(struct seq_file *m)
seq_printf(m, "bad");
seq_printf(m, "\n");
-#ifdef CONFIG_PREP_RESIDUAL
/* print info about SIMMs */
- if (res->ResidualLength != 0) {
+ if (have_residual_data) {
int i;
seq_printf(m, "simms\t\t: ");
for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
@@ -207,7 +207,13 @@ prep_ibm_cpuinfo(struct seq_file *m)
}
seq_printf(m, "\n");
}
-#endif
+}
+
+static int __prep
+prep_gen_cpuinfo(struct seq_file *m)
+{
+ prep_ibm_cpuinfo(m);
+ return 0;
}
static int __prep
@@ -431,9 +437,8 @@ prep_mot_cpuinfo(struct seq_file *m)
}
no_l2:
-#ifdef CONFIG_PREP_RESIDUAL
/* print info about SIMMs */
- if (res->ResidualLength != 0) {
+ if (have_residual_data) {
int i;
seq_printf(m, "simms\t\t: ");
for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
@@ -445,18 +450,11 @@ no_l2:
}
seq_printf(m, "\n");
}
-#endif
return 0;
}
static void __prep
-prep_tiger1_progress(char *msg, unsigned short code)
-{
- outw(code, PREP_IBM_DISP);
-}
-
-static void __prep
prep_restart(char *cmd)
{
#define PREP_SP92 0x92 /* Special Port 92 */
@@ -561,14 +559,12 @@ prep_show_percpuinfo(struct seq_file *m, int i)
{
/* PREP's without residual data will give incorrect values here */
seq_printf(m, "clock\t\t: ");
-#ifdef CONFIG_PREP_RESIDUAL
- if (res->ResidualLength)
+ if (have_residual_data)
seq_printf(m, "%ldMHz\n",
(res->VitalProductData.ProcessorHz > 1024) ?
res->VitalProductData.ProcessorHz / 1000000 :
res->VitalProductData.ProcessorHz);
else
-#endif /* CONFIG_PREP_RESIDUAL */
seq_printf(m, "???\n");
return 0;
@@ -598,9 +594,10 @@ static void __init prep_init_sound(void)
* Get the needed resource informations from residual data.
*
*/
-#ifdef CONFIG_PREP_RESIDUAL
- audiodevice = residual_find_device(~0, NULL, MultimediaController,
- AudioController, -1, 0);
+ if (have_residual_data)
+ audiodevice = residual_find_device(~0, NULL,
+ MultimediaController, AudioController, -1, 0);
+
if (audiodevice != NULL) {
PnP_TAG_PACKET *pkt;
@@ -613,7 +610,6 @@ static void __init prep_init_sound(void)
if (pkt != NULL)
ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
}
-#endif
/*
* These are the PReP specs' defaults for the cs4231. We use these
@@ -649,13 +645,14 @@ static void __init prep_init_sound(void)
static void __init
prep_init_vesa(void)
{
-#if defined(CONFIG_PREP_RESIDUAL) && \
- (defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA_16_MODULE) || \
+#if (defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA_16_MODULE) || \
defined(CONFIG_FB_VESA))
- PPC_DEVICE *vgadev;
+ PPC_DEVICE *vgadev = NULL;
+
+ if (have_residual_data)
+ vgadev = residual_find_device(~0, NULL, DisplayController,
+ SVGAController, -1, 0);
- vgadev = residual_find_device(~0, NULL, DisplayController, SVGAController,
- -1, 0);
if (vgadev != NULL) {
PnP_TAG_PACKET *pkt;
@@ -680,7 +677,112 @@ prep_init_vesa(void)
}
}
}
-#endif /* CONFIG_PREP_RESIDUAL */
+#endif
+}
+
+/*
+ * Set DBAT 2 to access 0x80000000 so early progress messages will work
+ */
+static __inline__ void
+prep_set_bat(void)
+{
+ /* wait for all outstanding memory access to complete */
+ mb();
+
+ /* setup DBATs */
+ mtspr(DBAT2U, 0x80001ffe);
+ mtspr(DBAT2L, 0x8000002a);
+
+ /* wait for updates */
+ mb();
+}
+
+/*
+ * IBM 3-digit status LED
+ */
+static unsigned int ibm_statusled_base __prepdata;
+
+static void __prep
+ibm_statusled_progress(char *s, unsigned short hex);
+
+static int __prep
+ibm_statusled_panic(struct notifier_block *dummy1, unsigned long dummy2,
+ void * dummy3)
+{
+ ibm_statusled_progress(NULL, 0x505); /* SOS */
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ibm_statusled_block __prepdata = {
+ ibm_statusled_panic,
+ NULL,
+ INT_MAX /* try to do it first */
+};
+
+static void __prep
+ibm_statusled_progress(char *s, unsigned short hex)
+{
+ static int notifier_installed;
+ /*
+ * Progress uses 4 digits and we have only 3. So, we map 0xffff to
+ * 0xfff for display switch off. Out of range values are mapped to
+ * 0xeff, as I'm told 0xf00 and above are reserved for hardware codes.
+ * Install the panic notifier when the display is first switched off.
+ */
+ if (hex == 0xffff) {
+ hex = 0xfff;
+ if (!notifier_installed) {
+ ++notifier_installed;
+ notifier_chain_register(&panic_notifier_list,
+ &ibm_statusled_block);
+ }
+ }
+ else
+ if (hex > 0xfff)
+ hex = 0xeff;
+
+ mb();
+ outw(hex, ibm_statusled_base);
+}
+
+static void __init
+ibm_statusled_init(void)
+{
+ /*
+ * The IBM 3-digit LED display is specified in the residual data
+ * as an operator panel device, type "System Status LED". Find
+ * that device and determine its address. We validate all the
+ * other parameters on the off-chance another, similar device
+ * exists.
+ */
+ if (have_residual_data) {
+ PPC_DEVICE *led;
+ PnP_TAG_PACKET *pkt;
+
+ led = residual_find_device(~0, NULL, SystemPeripheral,
+ OperatorPanel, SystemStatusLED, 0);
+ if (!led)
+ return;
+
+ pkt = PnP_find_packet((unsigned char *)
+ &res->DevicePnPHeap[led->AllocatedOffset], S8_Packet, 0);
+ if (!pkt)
+ return;
+
+ if (pkt->S8_Pack.IOInfo != ISAAddr16bit)
+ return;
+ if (*(unsigned short *)pkt->S8_Pack.RangeMin !=
+ *(unsigned short *)pkt->S8_Pack.RangeMax)
+ return;
+ if (pkt->S8_Pack.IOAlign != 2)
+ return;
+ if (pkt->S8_Pack.IONum != 2)
+ return;
+
+ ibm_statusled_base = ld_le16((unsigned short *)
+ (pkt->S8_Pack.RangeMin));
+ ppc_md.progress = ibm_statusled_progress;
+ }
}
static void __init
@@ -706,7 +808,7 @@ prep_setup_arch(void)
{
case _PREP_IBM:
reg = inb(PREP_IBM_PLANAR);
- printk(KERN_INFO "IBM planar ID: %08x", reg);
+ printk(KERN_INFO "IBM planar ID: %02x", reg);
switch (reg) {
case PREP_IBM_SANDALFOOT:
prep_gen_enable_l2();
@@ -721,7 +823,16 @@ prep_setup_arch(void)
ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo;
break;
default:
- printk(" -- unknown! Assuming Carolina");
+ if (have_residual_data) {
+ prep_gen_enable_l2();
+ setup_ibm_pci = prep_residual_setup_pci;
+ ppc_md.power_off = prep_halt;
+ ppc_md.show_cpuinfo = prep_gen_cpuinfo;
+ break;
+ }
+ else
+ printk(" - unknown! Assuming Carolina");
+ /* fall through */
case PREP_IBM_CAROLINA_IDE_0:
case PREP_IBM_CAROLINA_IDE_1:
case PREP_IBM_CAROLINA_IDE_2:
@@ -745,7 +856,6 @@ prep_setup_arch(void)
setup_ibm_pci = prep_tiger1_setup_pci;
ppc_md.power_off = prep_sig750_poweroff;
ppc_md.show_cpuinfo = prep_tiger1_cpuinfo;
- ppc_md.progress = prep_tiger1_progress;
break;
}
printk("\n");
@@ -808,8 +918,6 @@ prep_setup_arch(void)
/* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */
vgacon_remap_base = 0xf0000000;
conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
- conswitchp = &dummy_con;
#endif
}
@@ -821,18 +929,19 @@ prep_setup_arch(void)
static void __init
prep_calibrate_decr(void)
{
-#ifdef CONFIG_PREP_RESIDUAL
- unsigned long freq, divisor = 4;
-
- if ( res->VitalProductData.ProcessorBusHz ) {
- freq = res->VitalProductData.ProcessorBusHz;
- printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
- (freq/divisor)/1000000,
- (freq/divisor)%1000000);
- tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
- tb_ticks_per_jiffy = freq / HZ / divisor;
- } else
-#endif
+ if (have_residual_data) {
+ unsigned long freq, divisor = 4;
+
+ if ( res->VitalProductData.ProcessorBusHz ) {
+ freq = res->VitalProductData.ProcessorBusHz;
+ printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
+ (freq/divisor)/1000000,
+ (freq/divisor)%1000000);
+ tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+ tb_ticks_per_jiffy = freq / HZ / divisor;
+ }
+ }
+ else
todc_calibrate_decr();
}
@@ -863,6 +972,12 @@ prep_init_IRQ(void)
}
for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
irq_desc[i].handler = &i8259_pic;
+
+ if (have_residual_data) {
+ i8259_init(residual_isapic_addr());
+ return;
+ }
+
/* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory
* controller, we poll (as they have a different int-ack address). */
early_read_config_dword(NULL, 0, 0, PCI_VENDOR_ID, &pci_viddid);
@@ -1000,18 +1115,27 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
DMA_MODE_WRITE = 0x48;
/* figure out what kind of prep workstation we are */
-#ifdef CONFIG_PREP_RESIDUAL
- if ( res->ResidualLength != 0 ) {
+ if (have_residual_data) {
if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
_prep_type = _PREP_IBM;
else
_prep_type = _PREP_Motorola;
- } else /* assume motorola if no residual (netboot?) */
-#endif
- {
+ }
+ else {
+ /* assume motorola if no residual (netboot?) */
_prep_type = _PREP_Motorola;
}
+#ifdef CONFIG_PREP_PRESIDUAL
+ /* Switch off all residual data processing if the user requests it */
+ if (strstr(cmd_line, "noresidual") != NULL)
+ res = NULL;
+#endif
+
+ /* Initialise progress early to get maximum benefit */
+ prep_set_bat();
+ ibm_statusled_init();
+
ppc_md.setup_arch = prep_setup_arch;
ppc_md.show_percpuinfo = prep_show_percpuinfo;
ppc_md.show_cpuinfo = NULL; /* set in prep_setup_arch() */
diff --git a/arch/ppc/platforms/prpmc750.c b/arch/ppc/platforms/prpmc750.c
index e0ab8e301dedb..a75553c9a5ba7 100644
--- a/arch/ppc/platforms/prpmc750.c
+++ b/arch/ppc/platforms/prpmc750.c
@@ -193,10 +193,6 @@ static void __init prpmc750_setup_arch(void)
ROOT_DEV = Root_SDA2;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
OpenPIC_InitSenses = prpmc750_openpic_initsenses;
OpenPIC_NumInitSenses = sizeof(prpmc750_openpic_initsenses);
diff --git a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h
index 23ed94140c6e3..015b4f52c3eb1 100644
--- a/arch/ppc/platforms/prpmc750.h
+++ b/arch/ppc/platforms/prpmc750.h
@@ -5,20 +5,16 @@
*
* Author: Matt Porter <mporter@mvista.com>
*
- * Copyright 2001 MontaVista Software 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.
+ * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
*/
#ifdef __KERNEL__
#ifndef __ASM_PRPMC750_H__
#define __ASM_PRPMC750_H__
-#include <linux/serial_reg.h>
-
/*
* Due to limiations imposed by legacy hardware (primaryily IDE controllers),
* the PrPMC750 carrier board operates using a PReP address map.
@@ -81,5 +77,19 @@
#define PRPMC750_TBEN_REG 0xfef880c0
#define PRPMC750_TBEN_MASK 0x01
+/* UART Defines. */
+#define RS_TABLE_SIZE 4
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD (PRPMC750_BASE_BAUD / 16)
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+#define SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, PRPMC750_SERIAL_0, 1, STD_COM_FLAGS, \
+ iomem_base: (unsigned char *)PRPMC750_SERIAL_0, \
+ iomem_reg_shift: 4, \
+ io_type: SERIAL_IO_MEM } /* ttyS0 */
+
#endif /* __ASM_PRPMC750_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/prpmc750_serial.h b/arch/ppc/platforms/prpmc750_serial.h
deleted file mode 100644
index 9068cb0fe9580..0000000000000
--- a/arch/ppc/platforms/prpmc750_serial.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * include/asm-ppc/platforms/prpmc750_serial.h
- *
- * Motorola PrPMC750 serial support
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_PRPMC750_SERIAL_H__
-#define __ASM_PRPMC750_SERIAL_H__
-
-#include <linux/config.h>
-#include <platforms/prpmc750.h>
-
-#define RS_TABLE_SIZE 4
-
-/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
-#define BASE_BAUD (PRPMC750_BASE_BAUD / 16)
-
-#ifndef SERIAL_MAGIC_KEY
-#define kernel_debugger ppc_kernel_debug
-#endif
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-#define SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, PRPMC750_SERIAL_0, 1, STD_COM_FLAGS, \
- iomem_base: (unsigned char *)PRPMC750_SERIAL_0, \
- iomem_reg_shift: 4, \
- io_type: SERIAL_IO_MEM } /* ttyS0 */
-
-#endif /* __ASM_PRPMC750_SERIAL_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/prpmc800.c b/arch/ppc/platforms/prpmc800.c
index 0ffcfdfb1ad6f..0e99f8bc3f3ba 100644
--- a/arch/ppc/platforms/prpmc800.c
+++ b/arch/ppc/platforms/prpmc800.c
@@ -309,10 +309,6 @@ static void __init prpmc800_setup_arch(void)
ROOT_DEV = Root_SDA2;
#endif
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
printk(KERN_INFO "Port by MontaVista Software, Inc. "
"(source@mvista.com)\n");
}
diff --git a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h
index 4af2f2c9af071..e53ec9b42a354 100644
--- a/arch/ppc/platforms/prpmc800.h
+++ b/arch/ppc/platforms/prpmc800.h
@@ -5,12 +5,10 @@
*
* Author: Dale Farnsworth <dale.farnsworth@mvista.com>
*
- * Copyright 2001 MontaVista Software 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.
+ * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
*/
/*
* From Processor to PCI:
@@ -63,4 +61,22 @@
#define PRPMC800_INT_IRQ 16
#define PRPMC800_INT_PRI 15
+/* UART Defines. */
+#define RS_TABLE_SIZE 4
+
+/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
+#define BASE_BAUD (PRPMC800_BASE_BAUD / 16)
+
+#define STD_COM_FLAGS ASYNC_BOOT_AUTOCONF
+
+/* UARTS are at IRQ 16 */
+#define STD_SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, PRPMC800_SERIAL_1, 16, STD_COM_FLAGS, /* ttyS0 */\
+ iomem_base: (unsigned char *)PRPMC800_SERIAL_1, \
+ iomem_reg_shift: 0, \
+ io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS \
+ STD_SERIAL_PORT_DFNS
+
#endif /* __ASMPPC_PRPMC800_H */
diff --git a/arch/ppc/platforms/prpmc800_serial.h b/arch/ppc/platforms/prpmc800_serial.h
deleted file mode 100644
index 28231463e4efa..0000000000000
--- a/arch/ppc/platforms/prpmc800_serial.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/ppc/platforms/prpmc800_serial.h
- *
- * Definitions for Motorola MCG PRPMC800 cPCI board support
- *
- * Author: Dale Farnsworth dale.farnsworth@mvista.com
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __ASMPPC_PRPMC800_SERIAL_H
-#define __ASMPPC_PRPMC800_SERIAL_H
-
-#include <linux/config.h>
-#include <platforms/prpmc800.h>
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE 4
-#endif
-
-/* Rate for the 1.8432 Mhz clock for the onboard serial chip */
-#define BASE_BAUD (PRPMC800_BASE_BAUD / 16)
-
-#ifndef SERIAL_MAGIC_KEY
-#define kernel_debugger ppc_kernel_debug
-#endif
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-/* UARTS are at IRQ 16 */
-#define STD_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, PRPMC800_SERIAL_1, 16, STD_COM_FLAGS, /* ttyS0 */\
- iomem_base: (unsigned char *)PRPMC800_SERIAL_1, \
- iomem_reg_shift: 0, \
- io_type: SERIAL_IO_MEM },
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DFNS
-
-#endif /* __ASMPPC_PRPMC800_SERIAL_H */
diff --git a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c
index b094e27157fd5..1c3a0d9d02ba8 100644
--- a/arch/ppc/platforms/residual.c
+++ b/arch/ppc/platforms/residual.c
@@ -504,7 +504,7 @@ void __init print_residual_device_info(void)
#define did dev->DeviceId
/* make sure we have residual data first */
- if ( res->ResidualLength == 0 )
+ if (!have_residual_data)
return;
printk("Residual: %ld devices\n", res->ActualNumDevices);
@@ -639,7 +639,7 @@ void print_residual_device_info(void)
#define did dev->DeviceId
/* make sure we have residual data first */
- if ( res->ResidualLength == 0 )
+ if (!have_residual_data)
return;
printk("Residual: %ld devices\n", res->ActualNumDevices);
for ( i = 0;
@@ -790,7 +790,7 @@ PPC_DEVICE __init *residual_find_device(unsigned long BusMask,
int n)
{
int i;
- if ( !res->ResidualLength ) return NULL;
+ if (!have_residual_data) return NULL;
for (i=0; i<res->ActualNumDevices; i++) {
#define Dev res->Devices[i].DeviceId
if ( (Dev.BusId&BusMask) &&
@@ -813,7 +813,7 @@ PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
int n)
{
int i;
- if ( !res->ResidualLength ) return NULL;
+ if (!have_residual_data) return NULL;
for (i=0; i<res->ActualNumDevices; i++) {
#define Dev res->Devices[i].DeviceId
if ( (Dev.BusId&BusMask) &&
@@ -827,6 +827,129 @@ PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask,
return NULL;
}
+static int __init
+residual_scan_pcibridge(PnP_TAG_PACKET * pkt, struct pci_dev *dev)
+{
+ int irq = -1;
+
+#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData
+ if (dev->bus->number == data[16]) {
+ int i, size;
+
+ size = 3 + ld_le16((u_short *) (&pkt->L4_Pack.Count0));
+ for (i = 20; i < size - 4; i += 12) {
+ unsigned char pin;
+ int line_irq;
+
+ if (dev->devfn != data[i + 1])
+ continue;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ line_irq = ld_le16((unsigned short *)
+ (&data[i + 4 + 2 * (pin - 1)]));
+ irq = (line_irq == 0xffff) ? 0
+ : line_irq & 0x7fff;
+ } else
+ irq = 0;
+
+ break;
+ }
+ }
+#undef data
+
+ return irq;
+}
+
+int __init
+residual_pcidev_irq(struct pci_dev *dev)
+{
+ int i = 0;
+ int irq = -1;
+ PPC_DEVICE *bridge;
+
+ while ((bridge = residual_find_device
+ (-1, NULL, BridgeController, PCIBridge, -1, i++))) {
+
+ PnP_TAG_PACKET *pkt;
+ if (bridge->AllocatedOffset) {
+ pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+ bridge->AllocatedOffset, 3, 0);
+ if (!pkt)
+ continue;
+
+ irq = residual_scan_pcibridge(pkt, dev);
+ if (irq != -1)
+ break;
+ }
+ }
+
+ return (irq < 0) ? 0 : irq;
+}
+
+void __init residual_irq_mask(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+ PPC_DEVICE *dev;
+ int i = 0;
+ unsigned short irq_mask = 0x000; /* default to edge */
+
+ while ((dev = residual_find_device(-1, NULL, -1, -1, -1, i++))) {
+ PnP_TAG_PACKET *pkt;
+ unsigned short mask;
+ int size;
+ int offset = dev->AllocatedOffset;
+
+ if (!offset)
+ continue;
+
+ pkt = PnP_find_packet(res->DevicePnPHeap + offset,
+ IRQFormat, 0);
+ if (!pkt)
+ continue;
+
+ size = tag_small_count(pkt->S1_Pack.Tag) + 1;
+ mask = ld_le16((unsigned short *)pkt->S4_Pack.IRQMask);
+ if (size > 3 && (pkt->S4_Pack.IRQInfo & 0x0c))
+ irq_mask |= mask;
+ }
+
+ *irq_edge_mask_lo = irq_mask & 0xff;
+ *irq_edge_mask_hi = irq_mask >> 8;
+}
+
+unsigned int __init residual_isapic_addr(void)
+{
+ PPC_DEVICE *isapic;
+ PnP_TAG_PACKET *pkt;
+ unsigned int addr;
+
+ isapic = residual_find_device(~0, NULL, SystemPeripheral,
+ ProgrammableInterruptController,
+ ISA_PIC, 0);
+ if (!isapic)
+ goto unknown;
+
+ pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+ isapic->AllocatedOffset, 9, 0);
+ if (!pkt)
+ goto unknown;
+
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ /* Must be 32-bit memory address */
+ if (!((p.PPCData[0] == 2) && (p.PPCData[1] == 32)))
+ goto unknown;
+
+ /* It doesn't seem to work where length != 1 (what can I say? :-/ ) */
+ if (ld_le32((unsigned int *)(p.PPCData + 12)) != 1)
+ goto unknown;
+
+ addr = ld_le32((unsigned int *) (p.PPCData + 4));
+#undef p
+ return addr;
+unknown:
+ return 0;
+}
+
PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
unsigned packet_tag,
int n)
@@ -901,7 +1024,7 @@ static int proc_prep_residual_read(char * buf, char ** start, off_t off,
int __init
proc_prep_residual_init(void)
{
- if (res->ResidualLength)
+ if (have_residual_data)
create_proc_read_entry("residual", S_IRUGO, NULL,
proc_prep_residual_read, NULL);
return 0;
diff --git a/arch/ppc/platforms/rpx8260.c b/arch/ppc/platforms/rpx8260.c
deleted file mode 100644
index 07d78d49651cf..0000000000000
--- a/arch/ppc/platforms/rpx8260.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * arch/ppc/platforms/rpx8260.c
- *
- * RPC EP8260 platform support
- *
- * Author: Dan Malek <dan@embeddededge.com>
- * Derived from: pq2ads_setup.c by Kumar
- *
- * Copyright 2004 Embedded Edge, LLC
- *
- * 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.
- */
-
-#include <linux/config.h>
-#include <linux/seq_file.h>
-
-#include <asm/mpc8260.h>
-#include <asm/machdep.h>
-
-static void (*callback_setup_arch)(void);
-
-extern unsigned char __res[sizeof(bd_t)];
-
-extern void m8260_init(unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, unsigned long r7);
-
-static int
-ep8260_show_cpuinfo(struct seq_file *m)
-{
- bd_t *binfo = (bd_t *)__res;
-
- seq_printf(m, "vendor\t\t: RPC\n"
- "machine\t\t: EP8260 PPC\n"
- "\n"
- "mem size\t\t: 0x%08x\n"
- "console baud\t\t: %d\n"
- "\n",
- binfo->bi_memsize,
- binfo->bi_baudrate);
- return 0;
-}
-
-static void __init
-ep8260_setup_arch(void)
-{
- printk("RPC EP8260 Port\n");
- callback_setup_arch();
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- /* Generic 8260 platform initialization */
- m8260_init(r3, r4, r5, r6, r7);
-
- /* Anything special for this platform */
- ppc_md.show_cpuinfo = ep8260_show_cpuinfo;
-
- callback_setup_arch = ppc_md.setup_arch;
- ppc_md.setup_arch = ep8260_setup_arch;
-}
diff --git a/arch/ppc/platforms/rpx8260.h b/arch/ppc/platforms/rpx8260.h
index 7d5cd8893ac2d..843494a50ef3a 100644
--- a/arch/ppc/platforms/rpx8260.h
+++ b/arch/ppc/platforms/rpx8260.h
@@ -70,5 +70,12 @@ extern volatile u_char *rpx6_csr_addr;
#define PHY_INTERRUPT SIU_INT_IRQ7
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Embedded Planet"
+#define CPUINFO_MACHINE "EP8260 PowerPC"
+
+/* Warm reset vector. */
+#define BOOTROM_RESTART_ADDR ((uint)0xfff00104)
+
#endif /* __ASM_PLATFORMS_RPX8260_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c
index fdcbcf24004b4..d9307a261087f 100644
--- a/arch/ppc/platforms/sandpoint.c
+++ b/arch/ppc/platforms/sandpoint.c
@@ -303,10 +303,6 @@ sandpoint_setup_arch(void)
/* Lookup PCI host bridges */
sandpoint_find_bridges();
-#ifdef CONFIG_DUMMY_CONSOLE
- conswitchp = &dummy_con;
-#endif
-
printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c
index 6d101924a654b..41c8c6349c12c 100644
--- a/arch/ppc/platforms/sbc82xx.c
+++ b/arch/ppc/platforms/sbc82xx.c
@@ -16,10 +16,10 @@
*/
#include <linux/config.h>
-#include <linux/seq_file.h>
#include <linux/stddef.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <asm/mpc8260.h>
@@ -29,39 +29,12 @@
#include <asm/immap_cpm2.h>
#include <asm/pci.h>
-static void (*callback_setup_arch)(void);
static void (*callback_init_IRQ)(void);
extern unsigned char __res[sizeof(bd_t)];
-extern void m8260_init(unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, unsigned long r7);
-
extern void (*late_time_init)(void);
-static int
-sbc82xx_show_cpuinfo(struct seq_file *m)
-{
- bd_t *binfo = (bd_t *)__res;
-
- seq_printf(m, "vendor\t\t: Wind River\n"
- "machine\t\t: SBC PowerQUICC II\n"
- "\n"
- "mem size\t\t: 0x%08lx\n"
- "console baud\t\t: %ld\n"
- "\n",
- binfo->bi_memsize,
- binfo->bi_baudrate);
- return 0;
-}
-
-static void __init
-sbc82xx_setup_arch(void)
-{
- printk("SBC PowerQUICC II Port\n");
- callback_setup_arch();
-}
-
#ifdef CONFIG_GEN_RTC
TODC_ALLOC();
@@ -237,7 +210,6 @@ static int sbc82xx_pci_map_irq(struct pci_dev *dev, unsigned char idsel,
return PCI_IRQ_TABLE_LOOKUP;
}
-
static void __devinit quirk_sbc8260_cardbus(struct pci_dev *pdev)
{
uint32_t ctrl;
@@ -259,20 +231,13 @@ static void __devinit quirk_sbc8260_cardbus(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, quirk_sbc8260_cardbus);
void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
+m82xx_board_init(void)
{
- /* Generic 8260 platform initialization */
- m8260_init(r3, r4, r5, r6, r7);
-
/* u-boot may be using one of the FCC Ethernet devices.
Use the MAC address to the SCC. */
__res[offsetof(bd_t, bi_enetaddr[5])] &= ~3;
/* Anything special for this platform */
- ppc_md.show_cpuinfo = sbc82xx_show_cpuinfo;
-
- callback_setup_arch = ppc_md.setup_arch;
callback_init_IRQ = ppc_md.init_IRQ;
ppc_md.setup_arch = sbc82xx_setup_arch;
diff --git a/arch/ppc/platforms/sbc82xx.h b/arch/ppc/platforms/sbc82xx.h
index adafd49bed39e..e4042d4995f61 100644
--- a/arch/ppc/platforms/sbc82xx.h
+++ b/arch/ppc/platforms/sbc82xx.h
@@ -18,6 +18,10 @@
#define SBC82xx_MACADDR_NVRAM_FCC2 0x220000d5 /* JP7A */
#define SBC82xx_MACADDR_NVRAM_FCC3 0x220000db /* JP7B */
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Wind River"
+#define CPUINFO_MACHINE "SBC PowerQUICC II"
+
#define BOOTROM_RESTART_ADDR ((uint)0x40000104)
#define SBC82xx_PC_IRQA (NR_SIU_INTS+0)
diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
index ad671021e3b06..74be324564fa4 100644
--- a/arch/ppc/platforms/spruce.c
+++ b/arch/ppc/platforms/spruce.c
@@ -228,11 +228,6 @@ spruce_setup_arch(void)
ROOT_DEV = Root_SDA1;
#endif
-#ifdef CONFIG_VT
- conswitchp = &dummy_con;
-#endif
-
-
/* Identify the system */
printk(KERN_INFO "System Identification: IBM Spruce\n");
printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
diff --git a/arch/ppc/platforms/tqm8260.h b/arch/ppc/platforms/tqm8260.h
index 3366cbdedf3e3..c7a78a646c667 100644
--- a/arch/ppc/platforms/tqm8260.h
+++ b/arch/ppc/platforms/tqm8260.h
@@ -14,6 +14,10 @@
#define CPM_MAP_ADDR ((uint)0xFFF00000)
#define PHY_INTERRUPT 25
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "IN2 Systems"
+#define CPUINFO_MACHINE "TQM8260 PowerPC"
+
#define BOOTROM_RESTART_ADDR ((uint)0x40000104)
#endif /* __TQM8260_PLATFORM */
diff --git a/arch/ppc/platforms/tqm8260_setup.c b/arch/ppc/platforms/tqm8260_setup.c
index 1241ed5d46d8b..a8880bfc034b2 100644
--- a/arch/ppc/platforms/tqm8260_setup.c
+++ b/arch/ppc/platforms/tqm8260_setup.c
@@ -14,33 +14,12 @@
* option) any later version.
*/
-#include <linux/config.h>
-#include <linux/seq_file.h>
+#include <linux/init.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
#include <asm/machdep.h>
-static void (*callback_setup_arch)(void);
-
-extern unsigned char __res[sizeof(bd_t)];
-
-extern void m8260_init(unsigned long r3, unsigned long r4,
- unsigned long r5, unsigned long r6, unsigned long r7);
-
-static int
-tqm8260_show_cpuinfo(struct seq_file *m)
-{
- bd_t *binfo = (bd_t *)__res;
-
- seq_printf(m, "vendor\t\t: IN2 Systems\n"
- "machine\t\t: TQM8260 PowerPC\n"
- "mem size\t\t: 0x%08x\n"
- "\n",
- binfo->bi_memsize);
- return 0;
-}
-
static int
tqm8260_set_rtc_time(unsigned long time)
{
@@ -56,24 +35,10 @@ tqm8260_get_rtc_time(void)
return ((cpm2_map_t *)CPM_MAP_ADDR)->im_sit.sit_tmcnt;
}
-static void __init
-tqm8260_setup_arch(void)
-{
- printk("IN2 Systems TQM8260 port\n");
- callback_setup_arch();
-}
-
void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
+m82xx_board_init(void)
{
- /* Generic 8260 platform initialization */
- m8260_init(r3, r4, r5, r6, r7);
-
/* Anything special for this platform */
- ppc_md.show_cpuinfo = tqm8260_show_cpuinfo;
ppc_md.set_rtc_time = tqm8260_set_rtc_time;
ppc_md.get_rtc_time = tqm8260_get_rtc_time;
-
- callback_setup_arch = ppc_md.setup_arch;
- ppc_md.setup_arch = tqm8260_setup_arch;
+}
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 4de92f49857e2..fe15101b2485d 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -5,6 +5,8 @@
CFLAGS_prom_init.o += -fPIC
CFLAGS_btext.o += -fPIC
+wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o
+
obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o
obj-$(CONFIG_PPC_OCP) += ocp.o
obj-$(CONFIG_IBM_OCP) += ibm_ocp.o
@@ -22,7 +24,7 @@ obj-$(CONFIG_KGDB) += ppc4xx_kgdb.o
obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o ppc405_pci.o
endif
endif
-obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o
+obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y)
ifeq ($(CONFIG_8xx),y)
obj-$(CONFIG_PCI) += qspan_pci.o i8259.o
endif
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
index 43eac4135feff..bd8335b84d93a 100644
--- a/arch/ppc/syslib/cpm2_pic.c
+++ b/arch/ppc/syslib/cpm2_pic.c
@@ -1,12 +1,3 @@
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <asm/irq.h>
-#include <asm/immap_cpm2.h>
-#include <asm/mpc8260.h>
-#include "cpm2_pic.h"
-
/* The CPM2 internal interrupt controller. It is usually
* the only interrupt controller.
* There are two 32-bit registers (high/low) for up to 64
@@ -18,6 +9,18 @@
* We create two tables, indexed by vector number, to indicate
* which register to use and which bit in the register to use.
*/
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+
+#include <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+
+#include "cpm2_pic.h"
+
static u_char irq_to_siureg[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
@@ -123,9 +126,5 @@ cpm2_get_irq(struct pt_regs *regs)
if (irq == 0)
return(-1);
-#if 0
- irq += ppc8260_pic.irq_offset;
-#endif
return irq;
}
-
diff --git a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h
index a9da44168df2b..d05003b091f53 100644
--- a/arch/ppc/syslib/cpm2_pic.h
+++ b/arch/ppc/syslib/cpm2_pic.h
@@ -1,13 +1,7 @@
#ifndef _PPC_KERNEL_CPM2_H
#define _PPC_KERNEL_CPM2_H
-#include <linux/irq.h>
-
extern struct hw_interrupt_type cpm2_pic;
-
-void cpm2_pic_init(void);
-void cpm2_do_IRQ(struct pt_regs *regs,
- int cpu);
-int cpm2_get_irq(struct pt_regs *regs);
+extern int cpm2_get_irq(struct pt_regs *regs);
#endif /* _PPC_KERNEL_CPM2_H */
diff --git a/arch/ppc/syslib/hawk_common.c b/arch/ppc/syslib/hawk_common.c
index 9c2e1506a6d74..a9911dc3a82f9 100644
--- a/arch/ppc/syslib/hawk_common.c
+++ b/arch/ppc/syslib/hawk_common.c
@@ -285,3 +285,35 @@ hawk_get_mem_size(uint smc_base)
return total;
}
+
+int __init
+hawk_mpic_init(unsigned int pci_mem_offset)
+{
+ unsigned short devid;
+ unsigned int pci_membase;
+
+ /* Check the first PCI device to see if it is a Raven or Hawk. */
+ early_read_config_word(0, 0, 0, PCI_DEVICE_ID, &devid);
+
+ switch (devid) {
+ case PCI_DEVICE_ID_MOTOROLA_RAVEN:
+ case PCI_DEVICE_ID_MOTOROLA_HAWK:
+ break;
+ default:
+ OpenPIC_Addr = NULL;
+ return 1;
+ }
+
+ /* Read the memory base register. */
+ early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+ if (pci_membase == 0) {
+ OpenPIC_Addr = NULL;
+ return 1;
+ }
+
+ /* Map the MPIC registers to virtual memory. */
+ OpenPIC_Addr = ioremap(pci_membase + pci_mem_offset, 0x22000);
+
+ return 0;
+}
diff --git a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h
index 4e2ce7f7cdb31..d1352120acd7e 100644
--- a/arch/ppc/syslib/m8260_pci.h
+++ b/arch/ppc/syslib/m8260_pci.h
@@ -66,6 +66,7 @@
#endif
#ifdef CONFIG_8260_PCI9
+struct pci_controller;
extern void setup_m8260_indirect_pci(struct pci_controller* hose,
u32 cfg_addr, u32 cfg_data);
#else
diff --git a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c
index 24e1494c1c086..bfa66a235a378 100644
--- a/arch/ppc/syslib/m8260_setup.c
+++ b/arch/ppc/syslib/m8260_setup.c
@@ -1,5 +1,5 @@
/*
- * arch/ppc/kernel/setup.c
+ * arch/ppc/syslib/m8260_setup.c
*
* Copyright (C) 1995 Linus Torvalds
* Adapted from 'alpha' version by Gary Thomas
@@ -8,36 +8,20 @@
* Further modified for generic 8xx and 8260 by Dan.
*/
-/*
- * bootup setup stuff..
- */
-
#include <linux/config.h>
-#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/initrd.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
+#include <linux/irq.h>
#include <asm/mmu.h>
-#include <asm/residual.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/ide.h>
#include <asm/mpc8260.h>
#include <asm/immap_cpm2.h>
#include <asm/machdep.h>
@@ -46,10 +30,6 @@
#include "cpm2_pic.h"
-static int m8260_set_rtc_time(unsigned long time);
-static unsigned long m8260_get_rtc_time(void);
-static void m8260_calibrate_decr(void);
-
unsigned char __res[sizeof(bd_t)];
extern void cpm2_reset(void);
@@ -59,8 +39,10 @@ extern void idma_pci9_init(void);
static void __init
m8260_setup_arch(void)
{
- /* Reset the Communication Processor Module.
- */
+ /* Print out Vendor and Machine info. */
+ printk(KERN_INFO "%s %s port\n", CPUINFO_VENDOR, CPUINFO_MACHINE);
+
+ /* Reset the Communication Processor Module. */
cpm2_reset();
#ifdef CONFIG_8260_PCI9
/* Initialise IDMA for PCI erratum workaround */
@@ -69,6 +51,10 @@ m8260_setup_arch(void)
#ifdef CONFIG_PCI_8260
m8260_find_bridges();
#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+#endif
}
/* The decrementer counts at the system (internal) clock frequency
@@ -77,7 +63,7 @@ m8260_setup_arch(void)
static void __init
m8260_calibrate_decr(void)
{
- bd_t *binfo = (bd_t *)__res;
+ bd_t *binfo = (bd_t *)__res;
int freq, divisor;
freq = binfo->bi_busfreq;
@@ -145,18 +131,22 @@ m8260_power_off(void)
}
static int
-m8260_show_percpuinfo(struct seq_file *m, int i)
+m8260_show_cpuinfo(struct seq_file *m)
{
- bd_t *bp;
-
- bp = (bd_t *)__res;
-
- seq_printf(m, "core clock\t: %ld MHz\n"
- "CPM clock\t: %ld MHz\n"
- "bus clock\t: %ld MHz\n",
- bp->bi_intfreq / 1000000,
- bp->bi_cpmfreq / 1000000,
- bp->bi_busfreq / 1000000);
+ bd_t *bp = (bd_t *)__res;
+
+ seq_printf(m, "vendor\t\t: %s\n"
+ "machine\t\t: %s\n"
+ "\n"
+ "mem size\t\t: 0x%08x\n"
+ "console baud\t\t: %d\n"
+ "\n"
+ "core clock\t: %u MHz\n"
+ "CPM clock\t: %u MHz\n"
+ "bus clock\t: %u MHz\n",
+ CPUINFO_VENDOR, CPUINFO_MACHINE, bp->bi_memsize,
+ bp->bi_baudrate, bp->bi_intfreq / 1000000,
+ bp->bi_cpmfreq / 1000000, bp->bi_busfreq / 1000000);
return 0;
}
@@ -170,7 +160,6 @@ static void __init
m8260_init_IRQ(void)
{
int i;
- void cpm_interrupt_init(void);
for ( i = 0 ; i < NR_SIU_INTS ; i++ )
irq_desc[i].handler = &cpm2_pic;
@@ -190,10 +179,7 @@ m8260_init_IRQ(void)
static unsigned long __init
m8260_find_end_of_memory(void)
{
- bd_t *binfo;
- extern unsigned char __res[];
-
- binfo = (bd_t *)__res;
+ bd_t *binfo = (bd_t *)__res;
return binfo->bi_memsize;
}
@@ -216,6 +202,12 @@ m8260_map_io(void)
io_block_mapping(IO_VIRT_ADDR, IO_PHYS_ADDR, 0x10000000, _PAGE_IO);
}
+/* Place-holder for board-specific init */
+void __attribute__ ((weak)) __init
+m82xx_board_init(void)
+{
+}
+
/* Inputs:
* r3 - Optional pointer to a board information structure.
* r4 - Optional pointer to the physical starting address of the init RAM
@@ -228,7 +220,7 @@ m8260_map_io(void)
* command-line parameters.
*/
void __init
-m8260_init(unsigned long r3, unsigned long r4, unsigned long r5,
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
parse_bootinfo(find_bootinfo());
@@ -249,18 +241,18 @@ m8260_init(unsigned long r3, unsigned long r4, unsigned long r5,
strcpy(cmd_line, (char *)(r6+KERNELBASE));
}
+ /* Call back for board-specific settings. */
+ m82xx_board_init();
+
ppc_md.setup_arch = m8260_setup_arch;
- ppc_md.show_percpuinfo = m8260_show_percpuinfo;
- ppc_md.irq_canonicalize = NULL;
+ ppc_md.show_cpuinfo = m8260_show_cpuinfo;
ppc_md.init_IRQ = m8260_init_IRQ;
ppc_md.get_irq = cpm2_get_irq;
- ppc_md.init = NULL;
ppc_md.restart = m8260_restart;
ppc_md.power_off = m8260_power_off;
ppc_md.halt = m8260_halt;
- ppc_md.time_init = NULL;
ppc_md.set_rtc_time = m8260_set_rtc_time;
ppc_md.get_rtc_time = m8260_get_rtc_time;
ppc_md.calibrate_decr = m8260_calibrate_decr;
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 5ccf07149907d..0dc7889a85fe4 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -60,6 +60,11 @@ extern unsigned long find_available_memory(void);
extern void m8xx_cpm_reset(uint);
extern void rpxfb_alloc_pages(void);
+void __attribute__ ((weak))
+board_init(void)
+{
+}
+
void __init
m8xx_setup_arch(void)
{
@@ -102,6 +107,7 @@ m8xx_setup_arch(void)
}
#endif
#endif
+ board_init();
}
void
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
new file mode 100644
index 0000000000000..7838a44bfd1d3
--- /dev/null
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -0,0 +1,99 @@
+/*
+ * m8xx_wdt.c - MPC8xx watchdog driver
+ *
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/8xx_immap.h>
+#include <syslib/m8xx_wdt.h>
+
+static int wdt_timeout;
+
+void m8xx_wdt_reset(void)
+{
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+ imap->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */
+ imap->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */
+}
+
+static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+ m8xx_wdt_reset();
+
+ imap->im_sit.sit_piscr |= PISCR_PS; /* clear irq */
+
+ return IRQ_HANDLED;
+}
+
+void __init m8xx_wdt_handler_install(bd_t * binfo)
+{
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+ u32 pitc;
+ u32 sypcr;
+ u32 pitrtclk;
+
+ sypcr = imap->im_siu_conf.sc_sypcr;
+
+ if (!(sypcr & 0x04)) {
+ printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
+ sypcr);
+ return;
+ }
+
+ m8xx_wdt_reset();
+
+ printk(KERN_NOTICE
+ "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
+ (sypcr >> 16), sypcr & 0x01);
+
+ wdt_timeout = (sypcr >> 16) & 0xFFFF;
+
+ if (!wdt_timeout)
+ wdt_timeout = 0xFFFF;
+
+ if (sypcr & 0x01)
+ wdt_timeout *= 2048;
+
+ /*
+ * Fire trigger if half of the wdt ticked down
+ */
+
+ if (imap->im_sit.sit_rtcsc & RTCSC_38K)
+ pitrtclk = 9600;
+ else
+ pitrtclk = 8192;
+
+ if ((wdt_timeout) > (UINT_MAX / pitrtclk))
+ pitc = wdt_timeout / binfo->bi_intfreq * pitrtclk / 2;
+ else
+ pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2;
+
+ imap->im_sit.sit_pitc = pitc << 16;
+ imap->im_sit.sit_piscr =
+ (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE;
+
+ if (request_irq(PIT_INTERRUPT, m8xx_wdt_interrupt, 0, "watchdog", NULL))
+ panic("m8xx_wdt: could not allocate watchdog irq!");
+
+ printk(KERN_NOTICE
+ "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
+
+ wdt_timeout /= binfo->bi_intfreq;
+}
+
+int m8xx_wdt_get_timeout(void)
+{
+ return wdt_timeout;
+}
diff --git a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h
new file mode 100644
index 0000000000000..0d81a9f8155f1
--- /dev/null
+++ b/arch/ppc/syslib/m8xx_wdt.h
@@ -0,0 +1,16 @@
+/*
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#ifndef _PPC_SYSLIB_M8XX_WDT_H
+#define _PPC_SYSLIB_M8XX_WDT_H
+
+extern void m8xx_wdt_handler_install(bd_t * binfo);
+extern int m8xx_wdt_get_timeout(void);
+extern void m8xx_wdt_reset(void);
+
+#endif /* _PPC_SYSLIB_M8XX_WDT_H */
diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c
index f7458822f7b6b..735f3aec82c58 100644
--- a/arch/ppc/syslib/ppc4xx_setup.c
+++ b/arch/ppc/syslib/ppc4xx_setup.c
@@ -61,10 +61,6 @@ ppc4xx_setup_arch(void)
#ifdef CONFIG_PCI
ppc4xx_find_bridges();
#endif
-
-#if defined(CONFIG_FB)
- conswitchp = &dummy_con;
-#endif
}
/*
diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug
index 041c5a71d0ccf..2c72a73833d43 100644
--- a/arch/ppc64/Kconfig.debug
+++ b/arch/ppc64/Kconfig.debug
@@ -54,4 +54,16 @@ config SPINLINE
If in doubt, say N.
+config SCHEDSTATS
+ bool "Collect scheduler statistics"
+ depends on DEBUG_KERNEL && PROC_FS
+ help
+ If you say Y here, additional code will be inserted into the
+ scheduler and related routines to collect statistics about
+ scheduler behavior and provide them in /proc/schedstat. These
+ stats may be useful for both tuning and debugging the scheduler
+ If you aren't debugging the scheduler or trying to tune a specific
+ application, you can say N to avoid the very slight overhead
+ this adds.
+
endmenu
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index dc0885144293f..ce4fd6ff945d1 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -1037,6 +1037,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
* interrupts if necessary.
*/
beq .ret_from_except_lite
+ /* For a hash failure, we don't bother re-enabling interrupts */
+ ble- 12f
+
/*
* hash_page couldn't handle it, set soft interrupt enable back
* to what it was before the trap. Note that .local_irq_restore
@@ -1047,6 +1050,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
b 11f
#else
beq fast_exception_return /* Return from exception on success */
+ ble- 12f /* Failure return from hash_page */
+
/* fall through */
#endif
@@ -1066,6 +1071,15 @@ _GLOBAL(handle_page_fault)
bl .bad_page_fault
b .ret_from_except
+/* We have a page fault that hash_page could handle but HV refused
+ * the PTE insertion
+ */
+12: bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ lwz r4,_DAR(r1)
+ bl .low_hash_fault
+ b .ret_from_except
+
/* here we have a segment miss */
_GLOBAL(do_ste_alloc)
bl .ste_allocate /* try to insert stab entry */
diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
index a44c3326805e2..8303345d512f6 100644
--- a/arch/ppc64/kernel/pSeries_lpar.c
+++ b/arch/ppc64/kernel/pSeries_lpar.c
@@ -377,7 +377,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, lhpte.dw0.dword0,
lhpte.dw1.dword1, &slot, &dummy0, &dummy1);
- if (lpar_rc == H_PTEG_Full)
+ if (unlikely(lpar_rc == H_PTEG_Full))
return -1;
/*
@@ -385,7 +385,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
* will fail. However we must catch the failure in hash_page
* or we will loop forever, so return -2 in this case.
*/
- if (lpar_rc != H_Success)
+ if (unlikely(lpar_rc != H_Success))
return -2;
/* Because of iSeries, we have to pass down the secondary
@@ -415,9 +415,7 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
if (lpar_rc == H_Success)
return i;
- if (lpar_rc != H_Not_Found)
- panic("Bad return code from pte remove rc = %lx\n",
- lpar_rc);
+ BUG_ON(lpar_rc != H_Not_Found);
slot_offset++;
slot_offset &= 0x7;
@@ -447,8 +445,7 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp,
if (lpar_rc == H_Not_Found)
return -1;
- if (lpar_rc != H_Success)
- panic("bad return code from pte protect rc = %lx\n", lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
return 0;
}
@@ -467,8 +464,7 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot)
lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
- if (lpar_rc != H_Success)
- panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
return dword0;
}
@@ -519,15 +515,12 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
vpn = va >> PAGE_SHIFT;
slot = pSeries_lpar_hpte_find(vpn);
- if (slot == -1)
- panic("updateboltedpp: Could not find page to bolt\n");
+ BUG_ON(slot == -1);
flags = newpp & 3;
lpar_rc = plpar_pte_protect(flags, slot, 0);
- if (lpar_rc != H_Success)
- panic("Bad return code from pte bolted protect rc = %lx\n",
- lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
}
static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
@@ -546,8 +539,7 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
if (lpar_rc == H_Not_Found)
return;
- if (lpar_rc != H_Success)
- panic("Bad return code from invalidate rc = %lx\n", lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
}
/*
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
index 5acc56729160a..60a849279ed46 100644
--- a/arch/ppc64/kernel/process.c
+++ b/arch/ppc64/kernel/process.c
@@ -458,7 +458,7 @@ int sys_clone(unsigned long clone_flags, unsigned long p2, unsigned long p3,
}
}
- return do_fork(clone_flags & ~CLONE_IDLETASK, p2, regs, 0,
+ return do_fork(clone_flags, p2, regs, 0,
(int __user *)parent_tidptr, (int __user *)child_tidptr);
}
diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
index ac686cac70c76..63bac5fbd0816 100644
--- a/arch/ppc64/kernel/signal.c
+++ b/arch/ppc64/kernel/signal.c
@@ -459,17 +459,13 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
/* Set up Signal Frame */
setup_rt_frame(sig, ka, info, oldset, regs);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
- return;
}
static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
@@ -512,6 +508,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
{
siginfo_t info;
int signr;
+ struct k_sigaction ka;
/*
* If the current thread is 32 bit - invoke the
@@ -523,14 +520,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (!oldset)
oldset = &current->blocked;
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
- struct k_sigaction *ka = &current->sighand->action[signr-1];
-
/* Whee! Actually deliver the signal. */
if (TRAP(regs) == 0x0C00)
- syscall_restart(regs, ka);
- handle_signal(signr, ka, &info, oldset, regs);
+ syscall_restart(regs, &ka);
+ handle_signal(signr, &ka, &info, oldset, regs);
return 1;
}
diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
index 106f008afc6fa..2a165163df053 100644
--- a/arch/ppc64/kernel/signal32.c
+++ b/arch/ppc64/kernel/signal32.c
@@ -699,9 +699,7 @@ badframe:
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig)
@@ -864,9 +862,7 @@ badframe:
printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n",
regs, frame, *newspp);
#endif
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
@@ -928,18 +924,16 @@ badframe:
int do_signal32(sigset_t *oldset, struct pt_regs *regs)
{
siginfo_t info;
- struct k_sigaction *ka;
unsigned int frame, newsp;
int signr, ret;
+ struct k_sigaction ka;
if (!oldset)
oldset = &current->blocked;
newsp = frame = 0;
- signr = get_signal_to_deliver(&info, regs, NULL);
-
- ka = (signr == 0)? NULL: &current->sighand->action[signr-1];
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (TRAP(regs) == 0x0C00 /* System Call! */
&& regs->ccr & 0x10000000 /* error signalled */
@@ -950,7 +944,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
if (signr > 0
&& (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
|| (ret == ERESTARTSYS
- && !(ka->sa.sa_flags & SA_RESTART)))) {
+ && !(ka.sa.sa_flags & SA_RESTART)))) {
/* make the system call return an EINTR error */
regs->result = -EINTR;
regs->gpr[3] = EINTR;
@@ -969,7 +963,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
if (signr == 0)
return 0; /* no signals delivered */
- if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
+ if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
&& (!on_sig_stack(regs->gpr[1])))
newsp = (current->sas_ss_sp + current->sas_ss_size);
else
@@ -977,17 +971,15 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
newsp &= ~0xfUL;
/* Whee! Actually deliver the signal. */
- if (ka->sa.sa_flags & SA_SIGINFO)
- handle_rt_signal32(signr, ka, &info, oldset, regs, newsp);
+ if (ka.sa.sa_flags & SA_SIGINFO)
+ handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp);
else
- handle_signal32(signr, ka, &info, oldset, regs, newsp);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
+ handle_signal32(signr, &ka, &info, oldset, regs, newsp);
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ if (!(ka.sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigorsets(&current->blocked, &current->blocked,
+ &ka.sa.sa_mask);
sigaddset(&current->blocked, signr);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
index b72e964c3a122..f01708b1c0bb2 100644
--- a/arch/ppc64/kernel/smp.c
+++ b/arch/ppc64/kernel/smp.c
@@ -59,6 +59,7 @@ unsigned long cache_decay_ticks;
cpumask_t cpu_possible_map = CPU_MASK_NONE;
cpumask_t cpu_online_map = CPU_MASK_NONE;
+cpumask_t cpu_sibling_map[NR_CPUS] = { [0 ... NR_CPUS-1] = CPU_MASK_NONE };
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(cpu_possible_map);
@@ -800,21 +801,12 @@ static void __devinit smp_store_cpu_info(int id)
static void __init smp_create_idle(unsigned int cpu)
{
- struct pt_regs regs;
struct task_struct *p;
/* create a process for the processor */
- /* only regs.msr is actually used, and 0 is OK for it */
- memset(&regs, 0, sizeof(struct pt_regs));
- p = copy_process(CLONE_VM | CLONE_IDLETASK,
- 0, &regs, 0, NULL, NULL);
+ p = fork_idle(cpu);
if (IS_ERR(p))
panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
-
- wake_up_forked_process(p);
- init_idle(p, cpu);
- unhash_process(p);
-
paca[cpu].__current = p;
current_set[cpu] = p->thread_info;
}
@@ -859,6 +851,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
for_each_cpu(cpu)
if (cpu != boot_cpuid)
smp_create_idle(cpu);
+
+ for_each_cpu(cpu) {
+ cpu_set(cpu, cpu_sibling_map[cpu]);
+ if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
+ cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]);
+ }
}
void __devinit smp_prepare_boot_cpu(void)
@@ -1007,218 +1005,3 @@ void __init smp_cpus_done(unsigned int max_cpus)
set_cpus_allowed(current, old_mask);
}
-
-#ifdef CONFIG_SCHED_SMT
-#ifdef CONFIG_NUMA
-static struct sched_group sched_group_cpus[NR_CPUS];
-static struct sched_group sched_group_phys[NR_CPUS];
-static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static DEFINE_PER_CPU(struct sched_domain, node_domains);
-__init void arch_init_sched_domains(void)
-{
- int i;
- struct sched_group *first = NULL, *last = NULL;
-
- /* Set up domains */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
- struct sched_domain *node_domain = &per_cpu(node_domains, i);
- int node = cpu_to_node(i);
- cpumask_t nodemask = node_to_cpumask(node);
- cpumask_t my_cpumask = cpumask_of_cpu(i);
- cpumask_t sibling_cpumask = cpumask_of_cpu(i ^ 0x1);
-
- *cpu_domain = SD_SIBLING_INIT;
- if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
- cpus_or(cpu_domain->span, my_cpumask, sibling_cpumask);
- else
- cpu_domain->span = my_cpumask;
- cpu_domain->parent = phys_domain;
- cpu_domain->groups = &sched_group_cpus[i];
-
- *phys_domain = SD_CPU_INIT;
- phys_domain->span = nodemask;
- phys_domain->parent = node_domain;
- phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)];
-
- *node_domain = SD_NODE_INIT;
- node_domain->span = cpu_possible_map;
- node_domain->groups = &sched_group_nodes[node];
- }
-
- /* Set up CPU (sibling) groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- int j;
- first = last = NULL;
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- for_each_cpu_mask(j, cpu_domain->span) {
- struct sched_group *cpu = &sched_group_cpus[j];
-
- cpus_clear(cpu->cpumask);
- cpu_set(j, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- for (i = 0; i < MAX_NUMNODES; i++) {
- int j;
- cpumask_t nodemask;
- struct sched_group *node = &sched_group_nodes[i];
- cpumask_t node_cpumask = node_to_cpumask(i);
- cpus_and(nodemask, node_cpumask, cpu_possible_map);
-
- if (cpus_empty(nodemask))
- continue;
-
- first = last = NULL;
- /* Set up physical groups */
- for_each_cpu_mask(j, nodemask) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, j);
- struct sched_group *cpu = &sched_group_phys[j];
-
- if (j != first_cpu(cpu_domain->span))
- continue;
-
- cpu->cpumask = cpu_domain->span;
- /*
- * Make each extra sibling increase power by 10% of
- * the basic CPU. This is very arbitrary.
- */
- cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
- node->cpu_power += cpu->cpu_power;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- /* Set up nodes */
- first = last = NULL;
- for (i = 0; i < MAX_NUMNODES; i++) {
- struct sched_group *cpu = &sched_group_nodes[i];
- cpumask_t nodemask;
- cpumask_t node_cpumask = node_to_cpumask(i);
- cpus_and(nodemask, node_cpumask, cpu_possible_map);
-
- if (cpus_empty(nodemask))
- continue;
-
- cpu->cpumask = nodemask;
- /* ->cpu_power already setup */
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
-
- mb();
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_domain, i);
- }
-}
-#else /* !CONFIG_NUMA */
-static struct sched_group sched_group_cpus[NR_CPUS];
-static struct sched_group sched_group_phys[NR_CPUS];
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-__init void arch_init_sched_domains(void)
-{
- int i;
- struct sched_group *first = NULL, *last = NULL;
-
- /* Set up domains */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
- cpumask_t my_cpumask = cpumask_of_cpu(i);
- cpumask_t sibling_cpumask = cpumask_of_cpu(i ^ 0x1);
-
- *cpu_domain = SD_SIBLING_INIT;
- if (cur_cpu_spec->cpu_features & CPU_FTR_SMT)
- cpus_or(cpu_domain->span, my_cpumask, sibling_cpumask);
- else
- cpu_domain->span = my_cpumask;
- cpu_domain->parent = phys_domain;
- cpu_domain->groups = &sched_group_cpus[i];
-
- *phys_domain = SD_CPU_INIT;
- phys_domain->span = cpu_possible_map;
- phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)];
- }
-
- /* Set up CPU (sibling) groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- int j;
- first = last = NULL;
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- for_each_cpu_mask(j, cpu_domain->span) {
- struct sched_group *cpu = &sched_group_cpus[j];
-
- cpus_clear(cpu->cpumask);
- cpu_set(j, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- first = last = NULL;
- /* Set up physical groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_group *cpu = &sched_group_phys[i];
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- cpu->cpumask = cpu_domain->span;
- /* See SMT+NUMA setup for comment */
- cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
-
- mb();
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_domain, i);
- }
-}
-#endif /* CONFIG_NUMA */
-#endif /* CONFIG_SCHED_SMT */
diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S
index 1d9b61143aaac..6096266900d80 100644
--- a/arch/ppc64/kernel/vmlinux.lds.S
+++ b/arch/ppc64/kernel/vmlinux.lds.S
@@ -61,12 +61,6 @@ SECTIONS
__setup_end = .;
}
- __param : {
- __start___param = .;
- *(__param)
- __stop___param = .;
- }
-
.initcall.init : {
__initcall_start = .;
*(.initcall1.init)
diff --git a/arch/ppc64/mm/Makefile b/arch/ppc64/mm/Makefile
index 4e47f66faa0d1..d63dc4421f39a 100644
--- a/arch/ppc64/mm/Makefile
+++ b/arch/ppc64/mm/Makefile
@@ -5,6 +5,6 @@
EXTRA_CFLAGS += -mno-minimal-toc
obj-y := fault.o init.o imalloc.o hash_utils.o hash_low.o tlb.o \
- slb_low.o slb.o stab.o
+ slb_low.o slb.o stab.o mmap.o
obj-$(CONFIG_DISCONTIGMEM) += numa.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S
index 0d6b5c29b6457..93c868e687bb7 100644
--- a/arch/ppc64/mm/hash_low.S
+++ b/arch/ppc64/mm/hash_low.S
@@ -278,6 +278,10 @@ htab_wrong_access:
b bail
htab_pte_insert_failure:
- b .htab_insert_failure
+ /* Bail out restoring old PTE */
+ ld r6,STK_PARM(r6)(r1)
+ std r31,0(r6)
+ li r3,-1
+ b bail
diff --git a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c
index f405658406c38..842602152e9cc 100644
--- a/arch/ppc64/mm/hash_utils.c
+++ b/arch/ppc64/mm/hash_utils.c
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/cache.h>
#include <linux/init.h>
+#include <linux/signal.h>
#include <asm/ppcdebug.h>
#include <asm/processor.h>
@@ -236,14 +237,11 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
return pp;
}
-/*
- * Called by asm hashtable.S in case of critical insert failure
+/* Result code is:
+ * 0 - handled
+ * 1 - normal page fault
+ * -1 - critical hash insertion error
*/
-void htab_insert_failure(void)
-{
- panic("hash_page: pte_insert failed\n");
-}
-
int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
{
void *pgdir;
@@ -371,6 +369,25 @@ static inline void make_bl(unsigned int *insn_addr, void *func)
(unsigned long)insn_addr);
}
+/*
+ * low_hash_fault is called when we the low level hash code failed
+ * to instert a PTE due to an hypervisor error
+ */
+void low_hash_fault(struct pt_regs *regs, unsigned long address)
+{
+ if (user_mode(regs)) {
+ siginfo_t info;
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &info, current);
+ return;
+ }
+ bad_page_fault(regs, address, SIGBUS);
+}
+
void __init htab_finish_init(void)
{
extern unsigned int *htab_call_hpte_insert1;
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
index cbdea6090aba1..7ee7808010026 100644
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -613,7 +613,7 @@ void __init paging_init(void)
zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;
- free_area_init_node(0, &contig_page_data, NULL, zones_size,
+ free_area_init_node(0, &contig_page_data, zones_size,
__pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
mem_map = contig_page_data.node_mem_map;
}
diff --git a/arch/ppc64/mm/mmap.c b/arch/ppc64/mm/mmap.c
new file mode 100644
index 0000000000000..f90dd1f7ab569
--- /dev/null
+++ b/arch/ppc64/mm/mmap.c
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/ppc64/mm/mmap.c
+ *
+ * flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(void)
+{
+ unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+static inline int mmap_is_legacy(void)
+{
+ /*
+ * Force standard allocation for 64 bit programs.
+ */
+ if (!test_thread_flag(TIF_32BIT))
+ return 1;
+
+ if (current->personality & ADDR_COMPAT_LAYOUT)
+ return 1;
+
+ if (current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
+ return 1;
+
+ return sysctl_legacy_va_layout;
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ /*
+ * Fall back to the standard layout if the personality
+ * bit is set, or if the expected stack growth is unlimited:
+ */
+ if (mmap_is_legacy()) {
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base();
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
index eb33136944c40..ffc44e4ab6ab6 100644
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -442,7 +442,6 @@ void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES];
unsigned long zholes_size[MAX_NR_ZONES];
- struct page *node_mem_map;
int nid;
memset(zones_size, 0, sizeof(zones_size));
@@ -469,11 +468,11 @@ void __init paging_init(void)
* in free_area_init_node (which will fail).
*/
if (!node_data[nid].node_spanned_pages)
- node_mem_map = alloc_bootmem(sizeof(struct page));
+ NODE_DATA(nid)->node_mem_map
+ = alloc_bootmem(sizeof(struct page));
else
- node_mem_map = NULL;
-
- free_area_init_node(nid, NODE_DATA(nid), node_mem_map,
- zones_size, start_pfn, zholes_size);
+ NODE_DATA(nid)->node_mem_map = NULL;
+ free_area_init_node(nid, NODE_DATA(nid), zones_size,
+ start_pfn, zholes_size);
}
}
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index d4cd42c3e7920..a45a0283547e3 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -419,7 +419,6 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -511,11 +510,12 @@ CONFIG_CRYPTO=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES_GENERIC is not set
+# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 5685c5feb3c68..5c0a63aff9393 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -725,8 +725,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo)
int ret;
mm_segment_t old_fs = get_fs();
- if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
- copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
+ if (copy_siginfo_from_user32(&info, uinfo))
return -EFAULT;
set_fs (KERNEL_DS);
ret = sys_rt_sigqueueinfo(pid, sig, &info);
@@ -1219,7 +1218,7 @@ asmlinkage long sys32_clone(struct pt_regs regs)
child_tidptr = (int *) (regs.gprs[5] & 0x7fffffffUL);
if (!newsp)
newsp = regs.gprs[15];
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
+ return do_fork(clone_flags, newsp, &regs, 0,
parent_tidptr, child_tidptr);
}
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index e8c8b2fe7af57..44a307caf0c90 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -552,9 +552,7 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -604,9 +602,7 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
@@ -614,20 +610,15 @@ give_sigsegv:
*/
void
-handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset,
- struct pt_regs * regs)
+handle_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
- struct k_sigaction *ka = &current->sighand->action[sig-1];
-
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame32(sig, ka, info, oldset, regs);
else
setup_frame32(sig, ka, oldset, regs);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 73cb6baeb5259..c31efb82797e2 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -336,7 +336,7 @@ asmlinkage long sys_clone(struct pt_regs regs)
child_tidptr = (int __user *) regs.gprs[5];
if (!newsp)
newsp = regs.gprs[15];
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
+ return do_fork(clone_flags, newsp, &regs, 0,
parent_tidptr, child_tidptr);
}
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index d5b6481532ad3..179db7e039d86 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -358,9 +358,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -414,9 +412,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
@@ -424,20 +420,15 @@ give_sigsegv:
*/
static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
- struct pt_regs * regs)
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
- struct k_sigaction *ka = &current->sighand->action[sig-1];
-
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info, oldset, regs);
else
setup_frame(sig, ka, oldset, regs);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -461,6 +452,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
siginfo_t info;
int signr;
+ struct k_sigaction ka;
/*
* We want the common case to go fast, which
@@ -494,7 +486,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
/* Get signal to deliver. When running under ptrace, at this point
the debugger may change all our registers ... */
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
/* Depending on the signal settings we may need to revert the
decision to restart the system call. */
@@ -513,14 +505,15 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
#ifdef CONFIG_S390_SUPPORT
if (test_thread_flag(TIF_31BIT)) {
extern void handle_signal32(unsigned long sig,
+ struct k_sigaction *ka,
siginfo_t *info,
sigset_t *oldset,
struct pt_regs *regs);
- handle_signal32(signr, &info, oldset, regs);
+ handle_signal32(signr, &ka, &info, oldset, regs);
return 1;
}
#endif
- handle_signal(signr, &info, oldset, regs);
+ handle_signal(signr, &ka, &info, oldset, regs);
return 1;
}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index eb8a5161ab99e..7c184529ebcfe 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -562,21 +562,15 @@ int __devinit start_secondary(void *cpuvoid)
static void __init smp_create_idle(unsigned int cpu)
{
- struct pt_regs regs;
struct task_struct *p;
/*
* don't care about the psw and regs settings since we'll never
* reschedule the forked task.
*/
- memset(&regs, 0, sizeof(struct pt_regs));
- p = copy_process(CLONE_VM | CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+ p = fork_idle(cpu);
if (IS_ERR(p))
panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
-
- wake_up_forked_process(p);
- init_idle(p, cpu);
- unhash_process(p);
current_set[cpu] = p;
}
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index b4534b2867c37..2cbdff6e96606 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -78,9 +78,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index d9ccdbdc2c241..02d2179e40828 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -21,7 +21,7 @@
#include <asm/s390_ext.h>
#include <asm/timer.h>
-#define VTIMER_MAGIC (0x4b87ad6e + 1)
+#define VTIMER_MAGIC (TIMER_MAGIC + 1)
static ext_int_info_t ext_int_info_timer;
DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index f8583caa605c2..aa9a42b6e62d1 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -2,6 +2,6 @@
# Makefile for the linux s390-specific parts of the memory manager.
#
-obj-y := init.o fault.o ioremap.o extmem.o
+obj-y := init.o fault.o ioremap.o extmem.o mmap.o
obj-$(CONFIG_CMM) += cmm.o
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
new file mode 100644
index 0000000000000..1039196ef053b
--- /dev/null
+++ b/arch/s390/mm/mmap.c
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/s390/mm/mmap.c
+ *
+ * flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(void)
+{
+ unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur;
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+static inline int mmap_is_legacy(void)
+{
+#ifdef CONFIG_ARCH_S390X
+ /*
+ * Force standard allocation for 64 bit programs.
+ */
+ if (!test_thread_flag(TIF_31BIT))
+ return 1;
+#endif
+ return sysctl_legacy_va_layout ||
+ (current->personality & ADDR_COMPAT_LAYOUT) ||
+ current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY;
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ /*
+ * Fall back to the standard layout if the personality
+ * bit is set, or if the expected stack growth is unlimited:
+ */
+ if (mmap_is_legacy()) {
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base();
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 8ba6dd3009577..c9a43c8df32fb 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -440,7 +440,7 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
{
if (!newsp)
newsp = regs.regs[15];
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
+ return do_fork(clone_flags, newsp, &regs, 0,
(int __user *)parent_tidptr, (int __user *)child_tidptr);
}
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index ccee2eca5f599..fc5ef99602759 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -413,9 +413,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -490,9 +488,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index adb8eae9f39cc..9efe2b12fdd1e 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -98,19 +98,12 @@ void __devinit smp_prepare_boot_cpu(void)
int __cpu_up(unsigned int cpu)
{
struct task_struct *tsk;
- struct pt_regs regs;
- memset(&regs, 0, sizeof(struct pt_regs));
- tsk = copy_process(CLONE_VM | CLONE_IDLETASK, 0, &regs, 0, 0, 0);
+ tsk = fork_idle(cpu);
if (IS_ERR(tsk))
panic("Failed forking idle task for cpu %d\n", cpu);
- wake_up_forked_process(tsk);
-
- init_idle(tsk, cpu);
- unhash_process(tsk);
-
tsk->thread_info->cpu = cpu;
cpu_set(cpu, cpu_online_map);
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 92398074128ca..864a0f79e80c0 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -75,9 +75,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 7b49b6976e785..030008e1fd6c0 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -214,8 +214,8 @@ void __init paging_init(void)
*/
disable_mmu();
#endif
-
- free_area_init_node(0, NODE_DATA(0), 0, zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+ NODE_DATA(0)->node_mem_map = NULL;
+ free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
/* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/
mem_map = NODE_DATA(0)->node_mem_map;
@@ -225,7 +225,7 @@ void __init paging_init(void)
*/
zones_size[ZONE_DMA] = __MEMORY_SIZE_2ND >> PAGE_SHIFT;
zones_size[ZONE_NORMAL] = 0;
- free_area_init_node(1, NODE_DATA(1), 0, zones_size, __MEMORY_START_2ND >> PAGE_SHIFT, 0);
+ free_area_init_node(1, NODE_DATA(1), zones_size, __MEMORY_START_2ND >> PAGE_SHIFT, 0);
#endif
}
diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c
index f9e82274e35f4..001f125539072 100644
--- a/arch/sh64/kernel/process.c
+++ b/arch/sh64/kernel/process.c
@@ -820,7 +820,7 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
{
if (!newsp)
newsp = pregs->regs[15];
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, pregs, 0, 0, 0);
+ return do_fork(clone_flags, newsp, pregs, 0, 0, 0);
}
/*
diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
index 376b8998ba09a..a848fbdb1e4cb 100644
--- a/arch/sh64/kernel/signal.c
+++ b/arch/sh64/kernel/signal.c
@@ -520,9 +520,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -628,9 +626,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index a3fba816b48a5..53eea6ab010bc 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -106,9 +106,6 @@ SECTIONS
__setup_start = .;
.init.setup : C_PHYS(.init.setup) { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : C_PHYS(__param) { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : C_PHYS(.initcall.init) {
*(.initcall1.init)
diff --git a/arch/sh64/mm/init.c b/arch/sh64/mm/init.c
index 17cdeb425e058..09cd9c87907e8 100644
--- a/arch/sh64/mm/init.c
+++ b/arch/sh64/mm/init.c
@@ -122,8 +122,8 @@ void __init paging_init(void)
* All memory is good as ZONE_NORMAL (fall-through) and ZONE_DMA.
*/
zones_size[ZONE_DMA] = MAX_LOW_PFN - START_PFN;
-
- free_area_init_node(0, NODE_DATA(0), 0, zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+ NODE_DATA(0)->node_mem_map = NULL;
+ free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
/* XXX: MRB-remove - this doesn't seem sane, should this be done somewhere else ?*/
mem_map = NODE_DATA(0)->node_mem_map;
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 4ff019336e944..1dc918135eb33 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -435,8 +435,6 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
{
unsigned long parent_tid_ptr, child_tid_ptr;
- clone_flags &= ~CLONE_IDLETASK;
-
parent_tid_ptr = regs->u_regs[UREG_I2];
child_tid_ptr = regs->u_regs[UREG_I4];
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 1673a24569f06..276860da53bdb 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -274,7 +274,7 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
return;
segv_and_exit:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_sigreturn(struct pt_regs *regs)
@@ -341,7 +341,7 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
return;
segv_and_exit:
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
@@ -401,7 +401,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
spin_unlock_irq(&current->sighand->siglock);
return;
segv:
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
/* Checks if the fp is valid */
@@ -549,7 +549,7 @@ setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *old
sigill_and_return:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
@@ -663,7 +663,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
sigill_and_return:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signo, current);
}
static inline void
@@ -746,7 +746,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
sigill:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signo, current);
}
/* Setup a Solaris stack frame */
@@ -876,7 +876,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
sigill_and_return:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs)
@@ -889,7 +889,7 @@ asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs)
synchronize_user_stack();
if (current_thread_info()->w_saved)
- goto sigsegv_and_return;
+ return -EFAULT;
err = clear_user(uc, sizeof(*uc));
if (err)
@@ -930,9 +930,6 @@ asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs)
* we have already stuffed all of it with sync_user_stack
*/
return (err ? -EFAULT : 0);
-
-sigsegv_and_return:
- do_exit(SIGSEGV);
}
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
@@ -1018,7 +1015,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs)
return (err ? -EFAULT : 0);
sigsegv_and_return:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
static inline void
@@ -1036,8 +1033,6 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
else
setup_frame(&ka->sa, regs, signr, oldset, info);
}
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NOMASK)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -1077,6 +1072,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
{
siginfo_t info;
struct sparc_deliver_cookie cookie;
+ struct k_sigaction ka;
int signr;
/*
@@ -1096,15 +1092,12 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
if (!oldset)
oldset = &current->blocked;
- signr = get_signal_to_deliver(&info, regs, &cookie);
+ signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
if (signr > 0) {
- struct k_sigaction *ka;
-
- ka = &current->sighand->action[signr-1];
-
if (cookie.restart_syscall)
- syscall_restart(cookie.orig_i0, regs, &ka->sa);
- handle_signal(signr, ka, &info, oldset, regs, svr4_signal);
+ syscall_restart(cookie.orig_i0, regs, &ka.sa);
+ handle_signal(signr, &ka, &info, oldset,
+ regs, svr4_signal);
return 1;
}
if (cookie.restart_syscall &&
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 9f659c2f4196d..751b551da2b08 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -201,18 +201,9 @@ void __init smp4d_boot_cpus(void)
int no;
/* Cook up an idler for this guy. */
- kernel_thread(start_secondary, NULL, CLONE_IDLETASK);
-
+ p = fork_idle(i);
cpucount++;
-
- p = prev_task(&init_task);
-
- init_idle(p, i);
-
current_set[i] = p->thread_info;
-
- unhash_process(p);
-
for (no = 0; !cpu_find_by_instance(no, NULL, &mid)
&& mid != i; no++) ;
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index f2fc64edc773d..0975885dbb788 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -173,18 +173,9 @@ void __init smp4m_boot_cpus(void)
int timeout;
/* Cook up an idler for this guy. */
- kernel_thread(start_secondary, NULL, CLONE_IDLETASK);
-
+ p = fork_idle(i);
cpucount++;
-
- p = prev_task(&init_task);
-
- init_idle(p, i);
-
current_set[i] = p->thread_info;
-
- unhash_process(p);
-
/* See trampoline.S for details... */
entry += ((i-1) * 3);
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 8d4bbfaf304ca..61f4ff5712e0f 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -46,9 +46,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index c18475eaaee18..d5593b5d2e53d 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1341,7 +1341,7 @@ void __init srmmu_paging_init(void)
zones_size[ZONE_HIGHMEM] = npages;
zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
- free_area_init_node(0, &contig_page_data, NULL, zones_size,
+ free_area_init_node(0, &contig_page_data, zones_size,
pfn_base, zholes_size);
mem_map = contig_page_data.node_mem_map;
}
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index bf5ab8c4ce511..fd85c7b01714c 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -2114,7 +2114,7 @@ void __init sun4c_paging_init(void)
zones_size[ZONE_HIGHMEM] = npages;
zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
- free_area_init_node(0, &contig_page_data, NULL, zones_size,
+ free_area_init_node(0, &contig_page_data, zones_size,
pfn_base, zholes_size);
mem_map = contig_page_data.node_mem_map;
}
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 362e9a7025630..2694ee76ab48f 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,5 +1,7 @@
#
# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc1
+# Wed Aug 25 21:27:54 2004
#
CONFIG_64BIT=y
CONFIG_MMU=y
@@ -46,7 +48,7 @@ CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
#
-# General setup
+# General machine setup
#
CONFIG_BBC_I2C=m
CONFIG_VT=y
@@ -65,6 +67,7 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=m
+CONFIG_CPU_FREQ_GOV_ONDEMAND=m
# CONFIG_CPU_FREQ_24_API is not set
CONFIG_SPARC64=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -118,6 +121,7 @@ CONFIG_FW_LOADER=m
# Graphics support
#
CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_CIRRUS is not set
CONFIG_FB_PM2=y
# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
@@ -153,7 +157,6 @@ CONFIG_FB_FFB=y
#
# Console display driver support
#
-# CONFIG_MDA_CONSOLE is not set
# CONFIG_PROM_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -217,6 +220,7 @@ CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_UB=m
# CONFIG_BLK_DEV_RAM is not set
#
@@ -398,6 +402,7 @@ CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
CONFIG_MD_RAID5=m
CONFIG_MD_RAID6=m
CONFIG_MD_MULTIPATH=m
@@ -475,6 +480,7 @@ CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
+CONFIG_INET_TUNNEL=y
#
# IP: Virtual Server Configuration
@@ -514,6 +520,7 @@ CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_TUNNEL=m
CONFIG_IPV6_TUNNEL=m
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
@@ -580,6 +587,9 @@ CONFIG_IP_NF_TARGET_NOTRACK=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_REALM=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_MATCH_SCTP=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
#
# IPv6: Netfilter Configuration
@@ -1096,6 +1106,7 @@ CONFIG_I2C_CHARDEV=m
#
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ALGOPCA=m
#
# I2C Hardware Bus support
@@ -1120,6 +1131,7 @@ CONFIG_I2C_SIS96X=m
CONFIG_I2C_VIA=m
CONFIG_I2C_VIAPRO=m
CONFIG_I2C_VOODOO3=m
+CONFIG_I2C_PCA_ISA=m
#
# Hardware Sensors Chip support
@@ -1141,6 +1153,7 @@ CONFIG_SENSORS_LM83=m
CONFIG_SENSORS_LM85=m
CONFIG_SENSORS_LM90=m
CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_SMSC47M1=m
CONFIG_SENSORS_VIA686A=m
CONFIG_SENSORS_W83781D=m
CONFIG_SENSORS_W83L785TS=m
@@ -1263,6 +1276,7 @@ CONFIG_EXPORTFS=m
CONFIG_SUNRPC=m
CONFIG_SUNRPC_GSS=m
CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
CONFIG_SMB_FS=m
# CONFIG_SMB_NLS_DEFAULT is not set
CONFIG_CIFS=m
@@ -1734,14 +1748,14 @@ CONFIG_OPROFILE=m
# Kernel hacking
#
CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_SLAB is not set
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_DCFLUSH is not set
# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_DCFLUSH is not set
# CONFIG_STACK_DEBUG is not set
# CONFIG_DEBUG_BOOTMEM is not set
CONFIG_HAVE_DEC_LOCK=y
@@ -1762,6 +1776,7 @@ CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WHIRLPOOL=m
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 145ce7c730879..f3e3c657e9cb8 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -588,8 +588,6 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
{
int __user *parent_tid_ptr, *child_tid_ptr;
- clone_flags &= ~CLONE_IDLETASK;
-
#ifdef CONFIG_COMPAT
if (test_thread_flag(TIF_32BIT)) {
parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]);
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 07f0fb37d59db..d81bfab517f06 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -84,8 +84,8 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
regs->tnpc = npc;
err |= __get_user(regs->y, &((*grp)[MC_Y]));
err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
- regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
- regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
+ regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC);
+ regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2]));
err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3]));
@@ -135,7 +135,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
return;
do_sigsegv:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
asmlinkage void sparc64_get_context(struct pt_regs *regs)
@@ -226,7 +226,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
return;
do_sigsegv:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
struct rt_signal_frame {
@@ -408,9 +408,9 @@ void do_rt_sigreturn(struct pt_regs *regs)
err |= __get_user(tstate, &sf->regs.tstate);
err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs));
- /* User can only change condition codes in %tstate. */
- regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
- regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
+ /* User can only change condition codes and %asi in %tstate. */
+ regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC);
+ regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
@@ -439,7 +439,7 @@ void do_rt_sigreturn(struct pt_regs *regs)
spin_unlock_irq(&current->sighand->siglock);
return;
segv:
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
/* Checks if the fp is valid */
@@ -565,7 +565,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
sigill:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signo, current);
}
static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
@@ -574,8 +574,6 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
{
setup_rt_frame(ka, regs, signr, oldset,
(ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NOMASK)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -615,6 +613,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs * regs,
{
siginfo_t info;
struct signal_deliver_cookie cookie;
+ struct k_sigaction ka;
int signr;
cookie.restart_syscall = restart_syscall;
@@ -632,15 +631,11 @@ static int do_signal(sigset_t *oldset, struct pt_regs * regs,
}
#endif
- signr = get_signal_to_deliver(&info, regs, &cookie);
+ signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
if (signr > 0) {
- struct k_sigaction *ka;
-
- ka = &current->sighand->action[signr-1];
-
if (cookie.restart_syscall)
- syscall_restart(orig_i0, regs, &ka->sa);
- handle_signal(signr, ka, &info, oldset, regs);
+ syscall_restart(orig_i0, regs, &ka.sa);
+ handle_signal(signr, &ka, &info, oldset, regs);
return 1;
}
if (cookie.restart_syscall &&
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 4476451b9d9dc..3333571e736a4 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -59,6 +59,16 @@ struct signal_sframe32 {
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
};
+/* This magic should be in g_upper[0] for all upper parts
+ * to be valid.
+ */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
+typedef struct {
+ unsigned int g_upper[8];
+ unsigned int o_upper[8];
+ unsigned int asi;
+} siginfo_extra_v8plus_t;
+
/*
* And the new one, intended to be used for Linux applications only
* (we have enough in there to work with clone).
@@ -299,8 +309,13 @@ void do_new_sigreturn32(struct pt_regs *regs)
if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
err |= __get_user(i, &sf->v8plus.g_upper[0]);
if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+ unsigned long asi;
+
for (i = UREG_G1; i <= UREG_I7; i++)
err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+ err |= __get_user(asi, &sf->v8plus.asi);
+ regs->tstate &= ~TSTATE_ASI;
+ regs->tstate |= ((asi & 0xffUL) << 24UL);
}
}
@@ -330,7 +345,7 @@ void do_new_sigreturn32(struct pt_regs *regs)
return;
segv:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_sigreturn32(struct pt_regs *regs)
@@ -400,7 +415,7 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
return;
segv:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
@@ -447,8 +462,13 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
err |= __get_user(i, &sf->v8plus.g_upper[0]);
if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+ unsigned long asi;
+
for (i = UREG_G1; i <= UREG_I7; i++)
err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+ err |= __get_user(asi, &sf->v8plus.asi);
+ regs->tstate &= ~TSTATE_ASI;
+ regs->tstate |= ((asi & 0xffUL) << 24UL);
}
}
@@ -487,7 +507,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
spin_unlock_irq(&current->sighand->siglock);
return;
segv:
- do_exit(SIGSEGV);
+ force_sig(SIGSEGV, current);
}
/* Checks if the fp is valid */
@@ -648,7 +668,7 @@ setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *o
return;
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
@@ -715,7 +735,10 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
for (i = 1; i < 16; i++)
- err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+ err |= __put_user(((u32 *)regs->u_regs)[2*i],
+ &sf->v8plus.g_upper[i]);
+ err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
+ &sf->v8plus.asi);
if (psr & PSR_EF) {
err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -796,7 +819,7 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
sigill:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signo, current);
}
/* Setup a Solaris stack frame */
@@ -920,7 +943,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
return;
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
asmlinkage int
@@ -1071,7 +1094,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs)
return -EINTR;
sigsegv:
- do_exit(SIGSEGV);
+ return -EFAULT;
}
static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
@@ -1120,6 +1143,8 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
for (i = 1; i < 16; i++)
err |= __put_user(((u32 *)regs->u_regs)[2*i],
&sf->v8plus.g_upper[i]);
+ err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
+ &sf->v8plus.asi);
if (psr & PSR_EF) {
err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -1208,7 +1233,7 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
sigill:
do_exit(SIGILL);
sigsegv:
- do_exit(SIGSEGV);
+ force_sigsegv(signr, current);
}
static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
@@ -1227,8 +1252,6 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
else
setup_frame32(&ka->sa, regs, signr, oldset, info);
}
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NOMASK)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -1268,21 +1291,19 @@ int do_signal32(sigset_t *oldset, struct pt_regs * regs,
{
siginfo_t info;
struct signal_deliver_cookie cookie;
+ struct k_sigaction ka;
int signr;
int svr4_signal = current->personality == PER_SVR4;
cookie.restart_syscall = restart_syscall;
cookie.orig_i0 = orig_i0;
- signr = get_signal_to_deliver(&info, regs, &cookie);
+ signr = get_signal_to_deliver(&info, &ka, regs, &cookie);
if (signr > 0) {
- struct k_sigaction *ka;
-
- ka = &current->sighand->action[signr-1];
-
if (cookie.restart_syscall)
- syscall_restart32(orig_i0, regs, &ka->sa);
- handle_signal32(signr, ka, &info, oldset, regs, svr4_signal);
+ syscall_restart32(orig_i0, regs, &ka.sa);
+ handle_signal32(signr, &ka, &info, oldset,
+ regs, svr4_signal);
return 1;
}
if (cookie.restart_syscall &&
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index abc65dc6d61e7..fd36facd91749 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -303,14 +303,7 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
struct task_struct *p;
int timeout, ret, cpu_node;
- kernel_thread(NULL, NULL, CLONE_IDLETASK);
-
- p = prev_task(&init_task);
-
- init_idle(p, cpu);
-
- unhash_process(p);
-
+ p = fork_idle(cpu);
callin_flag = 0;
cpu_new_thread = p->thread_info;
cpu_set(cpu, cpu_callout_map);
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 8faeee09fab2d..136da98fca3b1 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -52,9 +52,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 60308cead4704..650d4ec4477c9 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1502,7 +1502,7 @@ void __init paging_init(void)
zones_size[ZONE_DMA] = npages;
zholes_size[ZONE_DMA] = npages - pages_avail;
- free_area_init_node(0, &contig_page_data, NULL, zones_size,
+ free_area_init_node(0, &contig_page_data, zones_size,
phys_base >> PAGE_SHIFT, zholes_size);
mem_map = contig_page_data.node_mem_map;
}
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 3fa8b154bf66c..fcf969e8e7f88 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -61,6 +61,20 @@ config MODE_SKAS
config NET
bool "Networking support"
+ help
+ Unless you really know what you are doing, you should say Y here.
+ The reason is that some programs need kernel networking support even
+ when running on a stand-alone machine that isn't connected to any
+ other computer. If you are upgrading from an older kernel, you
+ should consider updating your networking tools too because changes
+ in the kernel and the tools often go hand in hand. The tools are
+ contained in the package net-tools, the location and version number
+ of which are given in Documentation/Changes.
+
+ For a general introduction to Linux networking, it is highly
+ recommended to read the NET-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
source "fs/Kconfig.binfmt"
@@ -85,6 +99,19 @@ config HOSTFS
If you'd like to be able to work with files stored on the host,
say Y or M here; otherwise say N.
+config HPPFS
+ tristate "HoneyPot ProcFS"
+ help
+ hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
+ entries to be overridden, removed, or fabricated from the host.
+ Its purpose is to allow a UML to appear to be a physical machine
+ by removing or changing anything in /proc which gives away the
+ identity of a UML.
+
+ See http://user-mode-linux.sf.net/hppfs.html for more information.
+
+ You only need this if you are setting up a UML honeypot. Otherwise,
+ it is safe to say 'N' here.
config MCONSOLE
bool "Management console"
@@ -164,6 +191,17 @@ config KERNEL_STACK_ORDER
be 1 << order pages. The default is OK unless you're running Valgrind
on UML, in which case, set this to 3.
+config UML_REAL_TIME_CLOCK
+ bool "Real-time Clock"
+ default y
+ help
+ This option makes UML time deltas match wall clock deltas. This should
+ normally be enabled. The exception would be if you are debugging with
+ UML and spend long times with UML stopped at a breakpoint. In this
+ case, when UML is restarted, it will call the timer enough times to make
+ up for the time spent at the breakpoint. This could result in a
+ noticable lag. If this is a problem, then disable this option.
+
endmenu
source "init/Kconfig"
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index 9cbe43f1c631b..a2d58306d18d3 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -9,6 +9,10 @@ config FRAME_POINTER
config PT_PROXY
bool "Enable ptrace proxy"
depends on XTERM_CHAN && DEBUG_INFO
+ help
+ This option enables a debugging interface which allows gdb to debug
+ the kernel without needing to actually attach to kernel threads.
+ If you want to do kernel debugging, say Y here; otherwise say N.
config GPROF
bool "Enable gprof support"
diff --git a/arch/um/Kconfig_block b/arch/um/Kconfig_block
index fba53d9bb983d..ce872e1a6375f 100644
--- a/arch/um/Kconfig_block
+++ b/arch/um/Kconfig_block
@@ -29,6 +29,10 @@ config BLK_DEV_UBD_SYNC
wise choice too. In all other cases (for example, if you're just
playing around with User-Mode Linux) you can choose N.
+config BLK_DEV_COW_COMMON
+ bool
+ default BLK_DEV_UBD
+
config BLK_DEV_LOOP
tristate "Loopback device support"
diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char
index a21cbbc7efde6..1d5a0e54cce3a 100644
--- a/arch/um/Kconfig_char
+++ b/arch/um/Kconfig_char
@@ -108,11 +108,60 @@ config SSL_CHAN
config UNIX98_PTYS
bool "Unix98 PTY support"
-
-config UNIX98_PTY_COUNT
- int "Maximum number of Unix98 PTYs in use (0-2048)"
- depends on UNIX98_PTYS
+ ---help---
+ A pseudo terminal (PTY) is a software device consisting of two
+ halves: a master and a slave. The slave device behaves identical to
+ a physical terminal; the master device is used by a process to
+ read data from and write data to the slave, thereby emulating a
+ terminal. Typical programs for the master side are telnet servers
+ and xterms.
+
+ Linux has traditionally used the BSD-like names /dev/ptyxx for
+ masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+ has a number of problems. The GNU C library glibc 2.1 and later,
+ however, supports the Unix98 naming standard: in order to acquire a
+ pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+ terminal is then made available to the process and the pseudo
+ terminal slave can be accessed as /dev/pts/<number>. What was
+ traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+ All modern Linux systems use the Unix98 ptys. Say Y unless
+ you're on an embedded system and want to conserve memory.
+
+config LEGACY_PTYS
+ bool "Legacy (BSD) PTY support"
+ default y
+ ---help---
+ A pseudo terminal (PTY) is a software device consisting of two
+ halves: a master and a slave. The slave device behaves identical to
+ a physical terminal; the master device is used by a process to
+ read data from and write data to the slave, thereby emulating a
+ terminal. Typical programs for the master side are telnet servers
+ and xterms.
+
+ Linux has traditionally used the BSD-like names /dev/ptyxx
+ for masters and /dev/ttyxx for slaves of pseudo
+ terminals. This scheme has a number of problems, including
+ security. This option enables these legacy devices; on most
+ systems, it is safe to say N.
+
+
+config LEGACY_PTY_COUNT
+ int "Maximum number of legacy PTY in use"
+ depends on LEGACY_PTYS
default "256"
+ ---help---
+ The maximum number of legacy PTYs that can be used at any one time.
+ The default is 256, and should be more than enough. Embedded
+ systems may want to reduce this to save memory.
+
+ When not in use, each legacy PTY occupies 12 bytes on 32-bit
+ architectures and 24 bytes on 64-bit architectures.
+
+#config UNIX98_PTY_COUNT
+# int "Maximum number of Unix98 PTYs in use (0-2048)"
+# depends on UNIX98_PTYS
+# default "256"
config WATCHDOG
bool "Watchdog Timer Support"
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net
index 443a74bd622d7..94c6bf0986440 100644
--- a/arch/um/Kconfig_net
+++ b/arch/um/Kconfig_net
@@ -1,5 +1,5 @@
-menu "Network Devices"
+menu "UML Network Devices"
depends on NET
# UML virtual driver
@@ -176,73 +176,5 @@ config UML_NET_SLIRP
Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
-
-# Below are hardware-independent drivers mirrored from
-# drivers/net/Config.in. It would be nice if Linux
-# had HW independent drivers separated from the other
-# but it does not. Until then each non-ISA/PCI arch
-# needs to provide it's own menu of network drivers
-config DUMMY
- tristate "Dummy net driver support"
-
-config BONDING
- tristate "Bonding driver support"
-
-config EQUALIZER
- tristate "EQL (serial line load balancing) support"
-
-config TUN
- tristate "Universal TUN/TAP device driver support"
-
-config ETHERTAP
- tristate "Ethertap network tap (OBSOLETE)"
- depends on EXPERIMENTAL && NETLINK
-
-config PPP
- tristate "PPP (point-to-point protocol) support"
-
-config PPP_MULTILINK
- bool "PPP multilink support (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
-
-config PPP_FILTER
- bool "PPP filtering"
- depends on PPP && FILTER
-
-config PPP_ASYNC
- tristate "PPP support for async serial ports"
- depends on PPP
-
-config PPP_SYNC_TTY
- tristate "PPP support for sync tty ports"
- depends on PPP
-
-config PPP_DEFLATE
- tristate "PPP Deflate compression"
- depends on PPP
-
-config PPP_BSDCOMP
- tristate "PPP BSD-Compress compression"
- depends on PPP
-
-config PPPOE
- tristate "PPP over Ethernet (EXPERIMENTAL)"
- depends on PPP && EXPERIMENTAL
-
-config SLIP
- tristate "SLIP (serial line) support"
-
-config SLIP_COMPRESSED
- bool "CSLIP compressed headers"
- depends on SLIP=y
-
-config SLIP_SMART
- bool "Keepalive and linefill"
- depends on SLIP=y
-
-config SLIP_MODE_SLIP6
- bool "Six bit SLIP encapsulation"
- depends on SLIP=y
-
endmenu
diff --git a/arch/um/Makefile b/arch/um/Makefile
index fe9107b8a37e2..39957413464ca 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -22,17 +22,21 @@ core-y += $(ARCH_DIR)/kernel/ \
$(ARCH_DIR)/sys-$(SUBARCH)/
# Have to precede the include because the included Makefiles reference them.
-SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
- include/asm-um/sigcontext.h include/asm-um/processor.h \
- include/asm-um/ptrace.h include/asm-um/arch-signal.h
+SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \
+ arch-signal.h module.h
+SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header))
ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
-include $(ARCH_DIR)/Makefile-$(SUBARCH)
-include $(ARCH_DIR)/Makefile-os-$(OS)
+# This target adds dependencies to "prepare". They are defined in the included
+# Makefiles (see Makefile-i386).
+
+.PHONY: sys_prepare
+sys_prepare:
+ @:
MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt
MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas
@@ -41,6 +45,9 @@ ifneq ($(MAKEFILE-y),)
include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y))
endif
+include $(ARCH_DIR)/Makefile-$(SUBARCH)
+include $(ARCH_DIR)/Makefile-os-$(OS)
+
EXTRAVERSION := $(EXTRAVERSION)-1um
ARCH_INCLUDE = -I$(ARCH_DIR)/include
@@ -52,14 +59,22 @@ ARCH_INCLUDE = -I$(ARCH_DIR)/include
CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
-D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
- $(MODE_INCLUDE)
+ -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE)
+
+CFLAGS += $(call check_gcc,-fno-unit-at-a-time,)
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
+# These are needed for clean and mrproper, since in that case .config is not
+# included; the values here are meaningless
+
+CONFIG_NEST_LEVEL ?= 0
+CONFIG_KERNEL_HALF_GIGS ?= 0
+
SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
ifeq ($(CONFIG_MODE_SKAS), y)
-$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
+$(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
endif
include/linux/version.h: arch/$(ARCH)/Makefile
@@ -71,8 +86,6 @@ prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS)
LDFLAGS_vmlinux = -r
-vmlinux: $(ARCH_DIR)/main.o
-
# These aren't in Makefile-tt because they are needed in the !CONFIG_MODE_TT +
# CONFIG_MODE_SKAS + CONFIG_STATIC_LINK case.
@@ -98,55 +111,58 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT)
CONFIG_KERNEL_STACK_ORDER ?= 2
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
-CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \
+CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \
-DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
-DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \
- -DKERNEL_STACK_SIZE=$(STACK_SIZE)
-
-CPPFLAGS_$(LD_SCRIPT-y) = $(CPPFLAGS_vmlinux.lds) -P -C -Uum
+ -DKERNEL_STACK_SIZE=$(STACK_SIZE))
-LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y)
+export CPPFLAGS_$(LD_SCRIPT-y) = $(CPPFLAGS_vmlinux.lds) -P -C -Uum
-$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE
- $(call if_changed_dep,as_s_S)
+LD_SCRIPT-y := $(ARCH_DIR)/kernel/$(LD_SCRIPT-y)
linux: vmlinux $(LD_SCRIPT-y)
$(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \
- -o linux $(ARCH_DIR)/main.o vmlinux -L/usr/lib -lutil
+ -o linux vmlinux -L/usr/lib -lutil
USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
+USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS))
USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
$(MODE_INCLUDE)
# To get a definition of F_SETSIG
USER_CFLAGS += -D_GNU_SOURCE
+# From main Makefile, these options are set after including the ARCH makefile.
+# So copy them here.
+
+ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+USER_CFLAGS += -Os
+else
+USER_CFLAGS += -O2
+endif
+
+ifndef CONFIG_FRAME_POINTER
+USER_CFLAGS += -fomit-frame-pointer
+endif
+
+ifdef CONFIG_DEBUG_INFO
+USER_CFLAGS += -g
+endif
+
CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds \
- $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS)
+ $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \
+ $(GEN_HEADERS)
-$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
- $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
+ $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
archmrproper:
- for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
- do \
- $(MAKE) -C $$d archmrproper; \
- done
- rm -f $(CLEAN_FILES) $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
- $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
-
-archclean: sysclean
- for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
- do \
- $(MAKE) -C $$d clean; \
- done
- find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
- -o -name '*.gcov' \) -type f -print | xargs rm -f
- rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
+ @:
-archdep:
- for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done
+archclean:
+ @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
+ -o -name '*.gcov' \) -type f -print | xargs rm -f
$(SYMLINK_HEADERS):
cd $(TOPDIR)/$(dir $@) ; \
@@ -161,19 +177,32 @@ $(ARCH_DIR)/include/sysdep:
$(ARCH_DIR)/os:
cd $(ARCH_DIR) && ln -sf os-$(OS) os
-$(ARCH_DIR)/include/uml-config.h :
- sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@
+# Generated files
+define filechk_umlconfig
+ sed 's/ CONFIG/ UML_CONFIG/'
+endef
+
+$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h
+ $(call filechk,umlconfig)
+
+filechk_gen_header = $<
$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
- $< > $@
+ $(call filechk,gen_header)
$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
- $< > $@
+ $(call filechk,gen_header)
-$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \
- $(ARCH_DIR)/util FORCE ;
+$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \
+ sys_prepare FORCE ;
$(ARCH_DIR)/util: FORCE
- @$(call descend,$@,)
+ $(Q)$(MAKE) $(build)=$@
export SUBARCH USER_CFLAGS OS
+
+all: linux
+
+define archhelp
+ echo '* linux - Binary kernel image (./linux)'
+endef
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 3bd90fbdb7e05..ca6ebfe0d4ed2 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -16,22 +16,27 @@ SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util
SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
+sys_prepare: $(SYS_DIR)/sc.h
+
prepare: $(SYS_HEADERS)
+filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc
+
$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
- $< > $@
+ $(call filechk,$@)
+
+filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread
$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
- $< > $@
+ $(call filechk,$@)
-$(SYS_UTIL_DIR)/mk_sc: FORCE ;
- @$(call descend,$(SYS_UTIL_DIR),$@)
+$(SYS_UTIL_DIR)/mk_sc: scripts/basic/fixdep include/config/MARKER FORCE ;
+ $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
-$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ;
- @$(call descend,$(SYS_UTIL_DIR),$@)
+$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ;
+ $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
$(SYS_UTIL_DIR): include/asm FORCE
- @$(call descend,$@,)
+ $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR)
-sysclean :
- rm -f $(SYS_HEADERS)
+CLEAN_FILES += $(SYS_HEADERS)
diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas
index 55cba5e998e3f..b505e16c40012 100644
--- a/arch/um/Makefile-skas
+++ b/arch/um/Makefile-skas
@@ -14,7 +14,7 @@ MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include
LINK_SKAS = -Wl,-rpath,/lib
LD_SCRIPT_SKAS = dyn.lds
-GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
+GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
-$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
- $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
+$(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h :
+ $(Q)$(MAKE) $(build)=$(ARCH_DIR)/kernel/skas $@
diff --git a/arch/um/config.release b/arch/um/config.release
index 6d32bc20c682e..fc68bcb9294ed 100644
--- a/arch/um/config.release
+++ b/arch/um/config.release
@@ -227,7 +227,6 @@ CONFIG_ROMFS_FS=m
CONFIG_EXT2_FS=y
CONFIG_SYSV_FS=m
CONFIG_UDF_FS=m
-# CONFIG_UDF_RW is not set
CONFIG_UFS_FS=m
# CONFIG_UFS_FS_WRITE is not set
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 412d006b95b39..9384e87dbad2a 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,47 +1,77 @@
#
# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.8.1-mm3
+# Fri Aug 20 13:03:03 2004
#
CONFIG_USERMODE=y
CONFIG_MMU=y
-CONFIG_SWAP=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_CONFIG_LOG_BUF_SHIFT=14
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
#
-# General Setup
+# UML-specific options
#
CONFIG_MODE_TT=y
CONFIG_MODE_SKAS=y
CONFIG_NET=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
CONFIG_HOSTFS=y
+CONFIG_HPPFS=y
CONFIG_MCONSOLE=y
-CONFIG_MAGIC_SYSRQ=y
# CONFIG_HOST_2G_2G is not set
# CONFIG_UML_SMP is not set
# CONFIG_SMP is not set
CONFIG_NEST_LEVEL=0
CONFIG_KERNEL_HALF_GIGS=1
# CONFIG_HIGHMEM is not set
-CONFIG_PROC_MM=y
CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_UML_REAL_TIME_CLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CPUSETS is not set
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
# Loadable module support
#
-CONFIG_MODULES=y
-# CONFIG_KMOD is not set
+# CONFIG_MODULES is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
#
# Character Devices
@@ -58,7 +88,8 @@ CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
CONFIG_CON_CHAN="xterm"
CONFIG_SSL_CHAN="pty"
CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_WATCHDOG is not set
CONFIG_UML_SOUND=y
CONFIG_SOUND=y
@@ -69,6 +100,7 @@ CONFIG_HOSTAUDIO=y
#
CONFIG_BLK_DEV_UBD=y
# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_COW_COMMON=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y
@@ -78,7 +110,7 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_NETDEVICES=y
#
-# Network Devices
+# UML Network Devices
#
CONFIG_UML_NET=y
CONFIG_UML_NET_ETHERTAP=y
@@ -88,22 +120,6 @@ CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_MCAST=y
# CONFIG_UML_NET_PCAP is not set
CONFIG_UML_NET_SLIRP=y
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
-# CONFIG_ETHERTAP is not set
-CONFIG_PPP=y
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPPOE is not set
-CONFIG_SLIP=y
-# CONFIG_SLIP_COMPRESSED is not set
-# CONFIG_SLIP_SMART is not set
-# CONFIG_SLIP_MODE_SLIP6 is not set
#
# Networking support
@@ -115,8 +131,6 @@ CONFIG_SLIP=y
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
@@ -126,23 +140,24 @@ CONFIG_INET=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
-# CONFIG_XFRM_USER is not set
+# CONFIG_INET_IPCOMP is not set
# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
-CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
@@ -154,11 +169,24 @@ CONFIG_IPV6_SCTP__=y
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
#
# Ethernet (10 or 100Mbit)
@@ -170,83 +198,125 @@ CONFIG_IPV6_SCTP__=y
#
#
-# Wireless LAN (non-hamradio)
+# Ethernet (10000 Mbit)
#
-# CONFIG_NET_RADIO is not set
#
-# Token Ring devices (depends on LLC=y)
+# Token Ring devices
#
-# CONFIG_SHAPER is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
#
# File systems
#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_REISER4_FS=y
+CONFIG_REISER4_LARGE_KEY=y
+# CONFIG_REISER4_CHECK is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
CONFIG_QUOTACTL=y
-CONFIG_AUTOFS_FS=m
-CONFIG_AUTOFS4_FS=m
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
# CONFIG_EFS_FS is not set
CONFIG_JFFS_FS=y
CONFIG_JFFS_FS_VERBOSE=0
-CONFIG_JFFS_PROC_FS=y
+# CONFIG_JFFS_PROC_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=m
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_MINIX_FS=m
# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_XFS_FS is not set
#
# Network File Systems
#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
# CONFIG_EXPORTFS is not set
-# CONFIG_CIFS is not set
# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
#
@@ -254,11 +324,11 @@ CONFIG_EXT2_FS=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
#
# Native Language Support
#
+CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_CODEPAGE_437 is not set
# CONFIG_NLS_CODEPAGE_737 is not set
@@ -283,6 +353,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
@@ -301,6 +372,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Security options
#
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
@@ -311,33 +383,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Library routines
#
+# CONFIG_CRC_CCITT is not set
# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
#
# SCSI support
#
-CONFIG_SCSI=y
-CONFIG_GENERIC_ISA_DMA=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_SR_EXTRA_DEVS=2
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_DEBUG_QUEUES=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_DEBUG=y
+# CONFIG_SCSI is not set
#
# Multi-device support (RAID and LVM)
@@ -359,34 +412,46 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
#
# RAM/ROM/Flash chip drivers
#
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-CONFIG_MTD_BLKMTD=m
+CONFIG_MTD_BLKMTD=y
#
# Disk-On-Chip Device Drivers
#
-# CONFIG_MTD_DOC1000 is not set
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
#
# NAND Flash Device Drivers
@@ -396,6 +461,7 @@ CONFIG_MTD_BLKMTD=m
#
# Kernel hacking
#
+CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index 8ea9ada4a7218..127bb4d07c69a 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
@@ -15,7 +15,7 @@ mcast-objs := mcast_kern.o mcast_user.o
#pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
-hostaudio-objs := hostaudio_kern.o hostaudio_user.o
+hostaudio-objs := hostaudio_kern.o
ubd-objs := ubd_kern.o ubd_user.o
port-objs := port_kern.o port_user.o
harddog-objs := harddog_kern.o harddog_user.o
@@ -39,6 +39,7 @@ obj-$(CONFIG_PTY_CHAN) += pty.o
obj-$(CONFIG_TTY_CHAN) += tty.o
obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
obj-$(CONFIG_UML_WATCHDOG) += harddog.o
+obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
obj-y += stdio_console.o $(CHAN_OBJS)
@@ -46,18 +47,7 @@ USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
null.o pty.o tty.o xterm.o
-USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-clean:
-
-modules:
-
-fastdep:
-
-dep:
-
-archmrproper: clean
-
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 9e45a082e40c0..d48ff9e07a14b 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -8,6 +8,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/tty.h>
+#include <linux/string.h>
#include <linux/tty_flip.h>
#include <asm/irq.h>
#include "chan_kern.h"
@@ -16,6 +17,7 @@
#include "irq_user.h"
#include "sigio.h"
#include "line.h"
+#include "os.h"
static void *not_configged_init(char *str, int device, struct chan_opts *opts)
{
@@ -86,6 +88,52 @@ static struct chan_ops not_configged_ops = {
.winch = 0,
};
+void generic_close(int fd, void *unused)
+{
+ os_close_file(fd);
+}
+
+int generic_read(int fd, char *c_out, void *unused)
+{
+ int n;
+
+ n = os_read_file(fd, c_out, sizeof(*c_out));
+
+ if(n == -EAGAIN)
+ return(0);
+ else if(n == 0)
+ return(-EIO);
+ return(n);
+}
+
+int generic_write(int fd, const char *buf, int n, void *unused)
+{
+ return(os_write_file(fd, buf, n));
+}
+
+int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+ unsigned short *cols_out)
+{
+ int rows, cols;
+ int ret;
+
+ ret = os_window_size(fd, &rows, &cols);
+ if(ret < 0)
+ return(ret);
+
+ ret = ((*rows_out != rows) || (*cols_out != cols));
+
+ *rows_out = rows;
+ *cols_out = cols;
+
+ return(ret);
+}
+
+void generic_free(void *data)
+{
+ kfree(data);
+}
+
static void tty_receive_char(struct tty_struct *tty, char ch)
{
if(tty == NULL) return;
@@ -265,6 +313,11 @@ static int one_chan_config_string(struct chan *chan, char *str, int size,
{
int n = 0;
+ if(chan == NULL){
+ CONFIG_CHUNK(str, size, n, "none", 1);
+ return(n);
+ }
+
CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
if(chan->dev == NULL){
@@ -420,7 +473,8 @@ int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
INIT_LIST_HEAD(chans);
}
- if((out = strchr(str, ',')) != NULL){
+ out = strchr(str, ',');
+ if(out != NULL){
in = str;
*out = '\0';
out++;
@@ -475,12 +529,15 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
goto out;
}
err = chan->ops->read(chan->fd, &c, chan->data);
- if(err > 0) tty_receive_char(tty, c);
+ if(err > 0)
+ tty_receive_char(tty, c);
} while(err > 0);
+
if(err == 0) reactivate_fd(chan->fd, irq);
if(err == -EIO){
if(chan->primary){
- if(tty != NULL) tty_hangup(tty);
+ if(tty != NULL)
+ tty_hangup(tty);
line_disable(dev, irq);
close_chan(chans);
free_chan(chans);
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 714bace49972d..8a5180a779e57 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -7,7 +7,6 @@
#include <stdlib.h>
#include <errno.h>
#include <termios.h>
-#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
@@ -22,33 +21,6 @@
#include "choose-mode.h"
#include "mode.h"
-void generic_close(int fd, void *unused)
-{
- close(fd);
-}
-
-int generic_read(int fd, char *c_out, void *unused)
-{
- int n;
-
- n = read(fd, c_out, sizeof(*c_out));
- if(n < 0){
- if(errno == EAGAIN) return(0);
- return(-errno);
- }
- else if(n == 0) return(-EIO);
- return(1);
-}
-
-int generic_write(int fd, const char *buf, int n, void *unused)
-{
- int count;
-
- count = write(fd, buf, n);
- if(count < 0) return(-errno);
- return(count);
-}
-
int generic_console_write(int fd, const char *buf, int n, void *unused)
{
struct termios save, new;
@@ -65,26 +37,6 @@ int generic_console_write(int fd, const char *buf, int n, void *unused)
return(err);
}
-int generic_window_size(int fd, void *unused, unsigned short *rows_out,
- unsigned short *cols_out)
-{
- struct winsize size;
- int ret = 0;
-
- if(ioctl(fd, TIOCGWINSZ, &size) == 0){
- ret = ((*rows_out != size.ws_row) ||
- (*cols_out != size.ws_col));
- *rows_out = size.ws_row;
- *cols_out = size.ws_col;
- }
- return(ret);
-}
-
-void generic_free(void *data)
-{
- kfree(data);
-}
-
static void winch_handler(int sig)
{
}
@@ -100,14 +52,16 @@ static int winch_thread(void *arg)
struct winch_data *data = arg;
sigset_t sigs;
int pty_fd, pipe_fd;
+ int count, err;
char c = 1;
- close(data->close_me);
+ os_close_file(data->close_me);
pty_fd = data->pty_fd;
pipe_fd = data->pipe_fd;
- if(write(pipe_fd, &c, sizeof(c)) != sizeof(c))
+ count = os_write_file(pipe_fd, &c, sizeof(c));
+ if(count != sizeof(c))
printk("winch_thread : failed to write synchronization "
- "byte, errno = %d\n", errno);
+ "byte, err = %d\n", -count);
signal(SIGWINCH, winch_handler);
sigfillset(&sigs);
@@ -123,26 +77,24 @@ static int winch_thread(void *arg)
exit(1);
}
- if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){
- printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno);
- exit(1);
- }
- if(tcsetpgrp(pty_fd, os_getpid()) < 0){
- printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno);
+ err = os_new_tty_pgrp(pty_fd, os_getpid());
+ if(err < 0){
+ printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
exit(1);
}
- if(read(pipe_fd, &c, sizeof(c)) != sizeof(c))
+ count = os_read_file(pipe_fd, &c, sizeof(c));
+ if(count != sizeof(c))
printk("winch_thread : failed to read synchronization byte, "
- "errno = %d\n", errno);
+ "err = %d\n", -count);
while(1){
pause();
- if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){
- printk("winch_thread : write failed, errno = %d\n",
- errno);
- }
+ count = os_write_file(pipe_fd, &c, sizeof(c));
+ if(count != sizeof(c))
+ printk("winch_thread : write failed, err = %d\n",
+ -count);
}
}
@@ -154,8 +106,8 @@ static int winch_tramp(int fd, void *device_data, int *fd_out)
char c;
err = os_pipe(fds, 1, 1);
- if(err){
- printk("winch_tramp : os_pipe failed, errno = %d\n", -err);
+ if(err < 0){
+ printk("winch_tramp : os_pipe failed, err = %d\n", -err);
return(err);
}
@@ -168,12 +120,12 @@ static int winch_tramp(int fd, void *device_data, int *fd_out)
return(pid);
}
- close(fds[1]);
+ os_close_file(fds[1]);
*fd_out = fds[0];
- n = read(fds[0], &c, sizeof(c));
+ n = os_read_file(fds[0], &c, sizeof(c));
if(n != sizeof(c)){
printk("winch_tramp : failed to read synchronization byte\n");
- printk("read returned %d, errno = %d\n", n, errno);
+ printk("read failed, err = %d\n", -n);
printk("fd %d will not support SIGWINCH\n", fd);
*fd_out = -1;
}
@@ -183,20 +135,24 @@ static int winch_tramp(int fd, void *device_data, int *fd_out)
void register_winch(int fd, void *device_data)
{
int pid, thread, thread_fd;
+ int count;
char c = 1;
- if(!isatty(fd)) return;
+ if(!isatty(fd))
+ return;
pid = tcgetpgrp(fd);
- if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) &&
- (pid == -1)){
+ if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
+ device_data) && (pid == -1)){
thread = winch_tramp(fd, device_data, &thread_fd);
if(fd != -1){
register_winch_irq(thread_fd, fd, thread, device_data);
- if(write(thread_fd, &c, sizeof(c)) != sizeof(c))
+ count = os_write_file(thread_fd, &c, sizeof(c));
+ if(count != sizeof(c))
printk("register_winch : failed to write "
- "synchronization byte\n");
+ "synchronization byte, err = %d\n",
+ -count);
}
}
}
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
new file mode 100644
index 0000000000000..19517312aa863
--- /dev/null
+++ b/arch/um/drivers/cow.h
@@ -0,0 +1,41 @@
+#ifndef __COW_H__
+#define __COW_H__
+
+#include <asm/types.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define ntohll(x) bswap_64(x)
+# define htonll(x) bswap_64(x)
+#else
+#error "__BYTE_ORDER not defined"
+#endif
+
+extern int init_cow_file(int fd, char *cow_file, char *backing_file,
+ int sectorsize, int alignment, int *bitmap_offset_out,
+ unsigned long *bitmap_len_out, int *data_offset_out);
+
+extern int file_reader(__u64 offset, char *buf, int len, void *arg);
+extern int read_cow_header(int (*reader)(__u64, char *, int, void *),
+ void *arg, __u32 *version_out,
+ char **backing_file_out, time_t *mtime_out,
+ __u64 *size_out, int *sectorsize_out,
+ __u32 *align_out, int *bitmap_offset_out);
+
+extern int write_cow_header(char *cow_file, int fd, char *backing_file,
+ int sectorsize, int alignment, long long *size);
+
+extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
+ int bitmap_offset, unsigned long *bitmap_len_out,
+ int *data_offset_out);
+
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
new file mode 100644
index 0000000000000..ce251f08305fe
--- /dev/null
+++ b/arch/um/drivers/cow_sys.h
@@ -0,0 +1,48 @@
+#ifndef __COW_SYS_H__
+#define __COW_SYS_H__
+
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "user.h"
+
+static inline void *cow_malloc(int size)
+{
+ return(um_kmalloc(size));
+}
+
+static inline void cow_free(void *ptr)
+{
+ kfree(ptr);
+}
+
+#define cow_printf printk
+
+static inline char *cow_strdup(char *str)
+{
+ return(uml_strdup(str));
+}
+
+static inline int cow_seek_file(int fd, __u64 offset)
+{
+ return(os_seek_file(fd, offset));
+}
+
+static inline int cow_file_size(char *file, __u64 *size_out)
+{
+ return(os_file_size(file, size_out));
+}
+
+static inline int cow_write_file(int fd, char *buf, int size)
+{
+ return(os_write_file(fd, buf, size));
+}
+
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
new file mode 100644
index 0000000000000..84256290ff7cd
--- /dev/null
+++ b/arch/um/drivers/cow_user.c
@@ -0,0 +1,375 @@
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/user.h>
+#include <netinet/in.h>
+
+#include "os.h"
+
+#include "cow.h"
+#include "cow_sys.h"
+
+#define PATH_LEN_V1 256
+
+struct cow_header_v1 {
+ int magic;
+ int version;
+ char backing_file[PATH_LEN_V1];
+ time_t mtime;
+ __u64 size;
+ int sectorsize;
+};
+
+#define PATH_LEN_V2 MAXPATHLEN
+
+struct cow_header_v2 {
+ unsigned long magic;
+ unsigned long version;
+ char backing_file[PATH_LEN_V2];
+ time_t mtime;
+ __u64 size;
+ int sectorsize;
+};
+
+/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in
+ * case other systems have different values for MAXPATHLEN
+ */
+#define PATH_LEN_V3 4096
+
+/* Changes from V2 -
+ * PATH_LEN_V3 as described above
+ * Explicitly specify field bit lengths for systems with different
+ * lengths for the usual C types. Not sure whether char or
+ * time_t should be changed, this can be changed later without
+ * breaking compatibility
+ * Add alignment field so that different alignments can be used for the
+ * bitmap and data
+ * Add cow_format field to allow for the possibility of different ways
+ * of specifying the COW blocks. For now, the only value is 0,
+ * for the traditional COW bitmap.
+ * Move the backing_file field to the end of the header. This allows
+ * for the possibility of expanding it into the padding required
+ * by the bitmap alignment.
+ * The bitmap and data portions of the file will be aligned as specified
+ * by the alignment field. This is to allow COW files to be
+ * put on devices with restrictions on access alignments, such as
+ * /dev/raw, with a 512 byte alignment restriction. This also
+ * allows the data to be more aligned more strictly than on
+ * sector boundaries. This is needed for ubd-mmap, which needs
+ * the data to be page aligned.
+ * Fixed (finally!) the rounding bug
+ */
+
+struct cow_header_v3 {
+ __u32 magic;
+ __u32 version;
+ time_t mtime;
+ __u64 size;
+ __u32 sectorsize;
+ __u32 alignment;
+ __u32 cow_format;
+ char backing_file[PATH_LEN_V3];
+};
+
+/* COW format definitions - for now, we have only the usual COW bitmap */
+#define COW_BITMAP 0
+
+union cow_header {
+ struct cow_header_v1 v1;
+ struct cow_header_v2 v2;
+ struct cow_header_v3 v3;
+};
+
+#define COW_MAGIC 0x4f4f4f4d /* MOOO */
+#define COW_VERSION 3
+
+#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
+#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
+
+void cow_sizes(int version, __u64 size, int sectorsize, int align,
+ int bitmap_offset, unsigned long *bitmap_len_out,
+ int *data_offset_out)
+{
+ if(version < 3){
+ *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
+
+ *data_offset_out = bitmap_offset + *bitmap_len_out;
+ *data_offset_out = (*data_offset_out + sectorsize - 1) /
+ sectorsize;
+ *data_offset_out *= sectorsize;
+ }
+ else {
+ *bitmap_len_out = DIV_ROUND(size, sectorsize);
+ *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
+
+ *data_offset_out = bitmap_offset + *bitmap_len_out;
+ *data_offset_out = ROUND_UP(*data_offset_out, align);
+ }
+}
+
+static int absolutize(char *to, int size, char *from)
+{
+ char save_cwd[256], *slash;
+ int remaining;
+
+ if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
+ cow_printf("absolutize : unable to get cwd - errno = %d\n",
+ errno);
+ return(-1);
+ }
+ slash = strrchr(from, '/');
+ if(slash != NULL){
+ *slash = '\0';
+ if(chdir(from)){
+ *slash = '/';
+ cow_printf("absolutize : Can't cd to '%s' - "
+ "errno = %d\n", from, errno);
+ return(-1);
+ }
+ *slash = '/';
+ if(getcwd(to, size) == NULL){
+ cow_printf("absolutize : unable to get cwd of '%s' - "
+ "errno = %d\n", from, errno);
+ return(-1);
+ }
+ remaining = size - strlen(to);
+ if(strlen(slash) + 1 > remaining){
+ cow_printf("absolutize : unable to fit '%s' into %d "
+ "chars\n", from, size);
+ return(-1);
+ }
+ strcat(to, slash);
+ }
+ else {
+ if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
+ cow_printf("absolutize : unable to fit '%s' into %d "
+ "chars\n", from, size);
+ return(-1);
+ }
+ strcpy(to, save_cwd);
+ strcat(to, "/");
+ strcat(to, from);
+ }
+ chdir(save_cwd);
+ return(0);
+}
+
+int write_cow_header(char *cow_file, int fd, char *backing_file,
+ int sectorsize, int alignment, long long *size)
+{
+ struct cow_header_v3 *header;
+ unsigned long modtime;
+ int err;
+
+ err = cow_seek_file(fd, 0);
+ if(err < 0){
+ cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
+ goto out;
+ }
+
+ err = -ENOMEM;
+ header = cow_malloc(sizeof(*header));
+ if(header == NULL){
+ cow_printf("Failed to allocate COW V3 header\n");
+ goto out;
+ }
+ header->magic = htonl(COW_MAGIC);
+ header->version = htonl(COW_VERSION);
+
+ err = -EINVAL;
+ if(strlen(backing_file) > sizeof(header->backing_file) - 1){
+ cow_printf("Backing file name \"%s\" is too long - names are "
+ "limited to %d characters\n", backing_file,
+ sizeof(header->backing_file) - 1);
+ goto out_free;
+ }
+
+ if(absolutize(header->backing_file, sizeof(header->backing_file),
+ backing_file))
+ goto out_free;
+
+ err = os_file_modtime(header->backing_file, &modtime);
+ if(err < 0){
+ cow_printf("Backing file '%s' mtime request failed, "
+ "err = %d\n", header->backing_file, -err);
+ goto out_free;
+ }
+
+ err = cow_file_size(header->backing_file, size);
+ if(err < 0){
+ cow_printf("Couldn't get size of backing file '%s', "
+ "err = %d\n", header->backing_file, -err);
+ goto out_free;
+ }
+
+ header->mtime = htonl(modtime);
+ header->size = htonll(*size);
+ header->sectorsize = htonl(sectorsize);
+ header->alignment = htonl(alignment);
+ header->cow_format = COW_BITMAP;
+
+ err = os_write_file(fd, header, sizeof(*header));
+ if(err != sizeof(*header)){
+ cow_printf("Write of header to new COW file '%s' failed, "
+ "err = %d\n", cow_file, -err);
+ goto out_free;
+ }
+ err = 0;
+ out_free:
+ cow_free(header);
+ out:
+ return(err);
+}
+
+int file_reader(__u64 offset, char *buf, int len, void *arg)
+{
+ int fd = *((int *) arg);
+
+ return(pread(fd, buf, len, offset));
+}
+
+/* XXX Need to sanity-check the values read from the header */
+
+int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
+ __u32 *version_out, char **backing_file_out,
+ time_t *mtime_out, __u64 *size_out,
+ int *sectorsize_out, __u32 *align_out,
+ int *bitmap_offset_out)
+{
+ union cow_header *header;
+ char *file;
+ int err, n;
+ unsigned long version, magic;
+
+ header = cow_malloc(sizeof(*header));
+ if(header == NULL){
+ cow_printf("read_cow_header - Failed to allocate header\n");
+ return(-ENOMEM);
+ }
+ err = -EINVAL;
+ n = (*reader)(0, (char *) header, sizeof(*header), arg);
+ if(n < offsetof(typeof(header->v1), backing_file)){
+ cow_printf("read_cow_header - short header\n");
+ goto out;
+ }
+
+ magic = header->v1.magic;
+ if(magic == COW_MAGIC) {
+ version = header->v1.version;
+ }
+ else if(magic == ntohl(COW_MAGIC)){
+ version = ntohl(header->v1.version);
+ }
+ /* No error printed because the non-COW case comes through here */
+ else goto out;
+
+ *version_out = version;
+
+ if(version == 1){
+ if(n < sizeof(header->v1)){
+ cow_printf("read_cow_header - failed to read V1 "
+ "header\n");
+ goto out;
+ }
+ *mtime_out = header->v1.mtime;
+ *size_out = header->v1.size;
+ *sectorsize_out = header->v1.sectorsize;
+ *bitmap_offset_out = sizeof(header->v1);
+ *align_out = *sectorsize_out;
+ file = header->v1.backing_file;
+ }
+ else if(version == 2){
+ if(n < sizeof(header->v2)){
+ cow_printf("read_cow_header - failed to read V2 "
+ "header\n");
+ goto out;
+ }
+ *mtime_out = ntohl(header->v2.mtime);
+ *size_out = ntohll(header->v2.size);
+ *sectorsize_out = ntohl(header->v2.sectorsize);
+ *bitmap_offset_out = sizeof(header->v2);
+ *align_out = *sectorsize_out;
+ file = header->v2.backing_file;
+ }
+ else if(version == 3){
+ if(n < sizeof(header->v3)){
+ cow_printf("read_cow_header - failed to read V2 "
+ "header\n");
+ goto out;
+ }
+ *mtime_out = ntohl(header->v3.mtime);
+ *size_out = ntohll(header->v3.size);
+ *sectorsize_out = ntohl(header->v3.sectorsize);
+ *align_out = ntohl(header->v3.alignment);
+ *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
+ file = header->v3.backing_file;
+ }
+ else {
+ cow_printf("read_cow_header - invalid COW version\n");
+ goto out;
+ }
+ err = -ENOMEM;
+ *backing_file_out = cow_strdup(file);
+ if(*backing_file_out == NULL){
+ cow_printf("read_cow_header - failed to allocate backing "
+ "file\n");
+ goto out;
+ }
+ err = 0;
+ out:
+ cow_free(header);
+ return(err);
+}
+
+int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
+ int alignment, int *bitmap_offset_out,
+ unsigned long *bitmap_len_out, int *data_offset_out)
+{
+ __u64 size, offset;
+ char zero = 0;
+ int err;
+
+ err = write_cow_header(cow_file, fd, backing_file, sectorsize,
+ alignment, &size);
+ if(err)
+ goto out;
+
+ *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
+ cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
+ bitmap_len_out, data_offset_out);
+
+ offset = *data_offset_out + size - sizeof(zero);
+ err = cow_seek_file(fd, offset);
+ if(err < 0){
+ cow_printf("cow bitmap lseek failed : err = %d\n", -err);
+ goto out;
+ }
+
+ /* does not really matter how much we write it is just to set EOF
+ * this also sets the entire COW bitmap
+ * to zero without having to allocate it
+ */
+ err = cow_write_file(fd, &zero, sizeof(zero));
+ if(err != sizeof(zero)){
+ cow_printf("Write of bitmap to new COW file '%s' failed, "
+ "err = %d\n", cow_file, -err);
+ err = -EINVAL;
+ goto out;
+ }
+
+ return(0);
+
+ out:
+ return(err);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index de71aec2d262e..cf15b4a8b5175 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -53,7 +53,8 @@ static int connect_to_switch(struct daemon_data *pri)
struct request_v3 req;
int fd, n, err;
- if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
+ pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(pri->control < 0){
printk("daemon_open : control socket failed, errno = %d\n",
errno);
return(-errno);
@@ -67,7 +68,8 @@ static int connect_to_switch(struct daemon_data *pri)
goto out;
}
- if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
+ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(fd < 0){
printk("daemon_open : data socket failed, errno = %d\n",
errno);
err = -errno;
@@ -91,18 +93,18 @@ static int connect_to_switch(struct daemon_data *pri)
req.version = SWITCH_VERSION;
req.type = REQ_NEW_CONTROL;
req.sock = *local_addr;
- n = write(pri->control, &req, sizeof(req));
+ n = os_write_file(pri->control, &req, sizeof(req));
if(n != sizeof(req)){
- printk("daemon_open : control setup request returned %d, "
- "errno = %d\n", n, errno);
+ printk("daemon_open : control setup request failed, err = %d\n",
+ -n);
err = -ENOTCONN;
goto out;
}
- n = read(pri->control, sun, sizeof(*sun));
+ n = os_read_file(pri->control, sun, sizeof(*sun));
if(n != sizeof(*sun)){
- printk("daemon_open : read of data socket returned %d, "
- "errno = %d\n", n, errno);
+ printk("daemon_open : read of data socket failed, err = %d\n",
+ -n);
err = -ENOTCONN;
goto out_close;
}
@@ -111,9 +113,9 @@ static int connect_to_switch(struct daemon_data *pri)
return(fd);
out_close:
- close(fd);
+ os_close_file(fd);
out:
- close(pri->control);
+ os_close_file(pri->control);
return(err);
}
@@ -153,8 +155,8 @@ static void daemon_remove(void *data)
{
struct daemon_data *pri = data;
- close(pri->fd);
- close(pri->control);
+ 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);
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 4ac314c1aa548..33c6c7868ce25 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -35,7 +35,8 @@ void *fd_init(char *str, int device, struct chan_opts *opts)
printk("fd_init : couldn't parse file descriptor '%s'\n", str);
return(NULL);
}
- if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+ data = um_kmalloc(sizeof(*data));
+ if(data == NULL) return(NULL);
*data = ((struct fd_chan) { .fd = n,
.raw = opts->raw });
return(data);
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
index cbbf41b5f397a..d934181b8d4c6 100644
--- a/arch/um/drivers/harddog_user.c
+++ b/arch/um/drivers/harddog_user.c
@@ -27,10 +27,10 @@ static void pre_exec(void *d)
dup2(data->stdin, 0);
dup2(data->stdout, 1);
dup2(data->stdout, 2);
- close(data->stdin);
- close(data->stdout);
- close(data->close_me[0]);
- close(data->close_me[1]);
+ os_close_file(data->stdin);
+ os_close_file(data->stdout);
+ os_close_file(data->close_me[0]);
+ os_close_file(data->close_me[1]);
}
int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
@@ -44,15 +44,15 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
char **args = NULL;
err = os_pipe(in_fds, 1, 0);
- if(err){
- printk("harddog_open - os_pipe failed, errno = %d\n", -err);
- return(err);
+ if(err < 0){
+ printk("harddog_open - os_pipe failed, err = %d\n", -err);
+ goto out;
}
err = os_pipe(out_fds, 1, 0);
- if(err){
- printk("harddog_open - os_pipe failed, errno = %d\n", -err);
- return(err);
+ if(err < 0){
+ printk("harddog_open - os_pipe failed, err = %d\n", -err);
+ goto out_close_in;
}
data.stdin = out_fds[0];
@@ -72,42 +72,47 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
pid = run_helper(pre_exec, &data, args, NULL);
- close(out_fds[0]);
- close(in_fds[1]);
+ os_close_file(out_fds[0]);
+ os_close_file(in_fds[1]);
if(pid < 0){
err = -pid;
- printk("harddog_open - run_helper failed, errno = %d\n", err);
- goto out;
+ printk("harddog_open - run_helper failed, errno = %d\n", -err);
+ goto out_close_out;
}
- n = read(in_fds[0], &c, sizeof(c));
+ n = os_read_file(in_fds[0], &c, sizeof(c));
if(n == 0){
printk("harddog_open - EOF on watchdog pipe\n");
helper_wait(pid);
err = -EIO;
- goto out;
+ goto out_close_out;
}
else if(n < 0){
printk("harddog_open - read of watchdog pipe failed, "
- "errno = %d\n", errno);
+ "err = %d\n", -n);
helper_wait(pid);
- err = -errno;
- goto out;
+ err = n;
+ goto out_close_out;
}
*in_fd_ret = in_fds[0];
*out_fd_ret = out_fds[1];
return(0);
+
+ out_close_in:
+ os_close_file(in_fds[0]);
+ os_close_file(in_fds[1]);
+ out_close_out:
+ os_close_file(out_fds[0]);
+ os_close_file(out_fds[1]);
out:
- close(out_fds[1]);
- close(in_fds[0]);
return(err);
}
void stop_watchdog(int in_fd, int out_fd)
{
- close(in_fd);
- close(out_fd);
+ os_close_file(in_fd);
+ os_close_file(out_fd);
}
int ping_watchdog(int fd)
@@ -115,11 +120,12 @@ int ping_watchdog(int fd)
int n;
char c = '\n';
- n = write(fd, &c, sizeof(c));
- if(n < sizeof(c)){
- printk("ping_watchdog - write failed, errno = %d\n",
- errno);
- return(-errno);
+ n = os_write_file(fd, &c, sizeof(c));
+ if(n != sizeof(c)){
+ printk("ping_watchdog - write failed, err = %d\n", -n);
+ if(n < 0)
+ return(n);
+ return(-EIO);
}
return 1;
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index b512783a47fc5..03282cc42edaa 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -5,44 +5,64 @@
#include "linux/config.h"
#include "linux/module.h"
-#include "linux/version.h"
#include "linux/init.h"
#include "linux/slab.h"
#include "linux/fs.h"
#include "linux/sound.h"
#include "linux/soundcard.h"
+#include "asm/uaccess.h"
#include "kern_util.h"
#include "init.h"
-#include "hostaudio.h"
+#include "os.h"
+
+struct hostaudio_state {
+ int fd;
+};
+
+struct hostmixer_state {
+ int fd;
+};
+
+#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
+#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
/* Only changed from linux_main at boot time */
char *dsp = HOSTAUDIO_DEV_DSP;
char *mixer = HOSTAUDIO_DEV_MIXER;
+#define DSP_HELP \
+" This is used to specify the host dsp device to the hostaudio driver.\n" \
+" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
+
+#define MIXER_HELP \
+" This is used to specify the host mixer device to the hostaudio driver.\n" \
+" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
+
#ifndef MODULE
static int set_dsp(char *name, int *add)
{
- dsp = uml_strdup(name);
+ dsp = name;
return(0);
}
-__uml_setup("dsp=", set_dsp,
-"dsp=<dsp device>\n"
-" This is used to specify the host dsp device to the hostaudio driver.\n"
-" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
-);
+__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
static int set_mixer(char *name, int *add)
{
- mixer = uml_strdup(name);
+ mixer = name;
return(0);
}
-__uml_setup("mixer=", set_mixer,
-"mixer=<mixer device>\n"
-" This is used to specify the host mixer device to the hostaudio driver.\n"
-" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
-);
+__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
+
+#else /*MODULE*/
+
+MODULE_PARM(dsp, "s");
+MODULE_PARM_DESC(dsp, DSP_HELP);
+
+MODULE_PARM(mixer, "s");
+MODULE_PARM_DESC(mixer, MIXER_HELP);
+
#endif
/* /dev/dsp file operations */
@@ -51,23 +71,55 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count,
loff_t *ppos)
{
struct hostaudio_state *state = file->private_data;
+ void *kbuf;
+ int ret;
#ifdef DEBUG
printk("hostaudio: read called, count = %d\n", count);
#endif
- return(hostaudio_read_user(state, buffer, count, ppos));
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if(kbuf == NULL)
+ return(-ENOMEM);
+
+ ret = os_read_file(state->fd, kbuf, count);
+ if(ret < 0)
+ goto out;
+
+ if(copy_to_user(buffer, kbuf, ret))
+ ret = -EFAULT;
+
+ out:
+ kfree(kbuf);
+ return(ret);
}
static ssize_t hostaudio_write(struct file *file, const char *buffer,
size_t count, loff_t *ppos)
{
struct hostaudio_state *state = file->private_data;
+ void *kbuf;
+ int ret;
#ifdef DEBUG
printk("hostaudio: write called, count = %d\n", count);
#endif
- return(hostaudio_write_user(state, buffer, count, ppos));
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if(kbuf == NULL)
+ return(-ENOMEM);
+
+ ret = -EFAULT;
+ if(copy_from_user(kbuf, buffer, count))
+ goto out;
+
+ ret = os_write_file(state->fd, kbuf, count);
+ if(ret < 0)
+ goto out;
+
+ out:
+ kfree(kbuf);
+ return(ret);
}
static unsigned int hostaudio_poll(struct file *file,
@@ -86,12 +138,43 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct hostaudio_state *state = file->private_data;
+ unsigned long data = 0;
+ int ret;
#ifdef DEBUG
printk("hostaudio: ioctl called, cmd = %u\n", cmd);
#endif
-
- return(hostaudio_ioctl_user(state, cmd, arg));
+ switch(cmd){
+ case SNDCTL_DSP_SPEED:
+ case SNDCTL_DSP_STEREO:
+ case SNDCTL_DSP_GETBLKSIZE:
+ case SNDCTL_DSP_CHANNELS:
+ case SNDCTL_DSP_SUBDIVIDE:
+ case SNDCTL_DSP_SETFRAGMENT:
+ if(get_user(data, (int *) arg))
+ return(-EFAULT);
+ break;
+ default:
+ break;
+ }
+
+ ret = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
+
+ switch(cmd){
+ case SNDCTL_DSP_SPEED:
+ case SNDCTL_DSP_STEREO:
+ case SNDCTL_DSP_GETBLKSIZE:
+ case SNDCTL_DSP_CHANNELS:
+ case SNDCTL_DSP_SUBDIVIDE:
+ case SNDCTL_DSP_SETFRAGMENT:
+ if(put_user(data, (int *) arg))
+ return(-EFAULT);
+ break;
+ default:
+ break;
+ }
+
+ return(ret);
}
static int hostaudio_open(struct inode *inode, struct file *file)
@@ -110,12 +193,17 @@ static int hostaudio_open(struct inode *inode, struct file *file)
if(file->f_mode & FMODE_READ) r = 1;
if(file->f_mode & FMODE_WRITE) w = 1;
- ret = hostaudio_open_user(state, r, w, dsp);
+ ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
+
if(ret < 0){
+ printk("hostaudio_open failed to open '%s', err = %d\n",
+ dsp, -ret);
kfree(state);
return(ret);
}
+ state->fd = ret;
+
file->private_data = state;
return(0);
}
@@ -123,16 +211,19 @@ static int hostaudio_open(struct inode *inode, struct file *file)
static int hostaudio_release(struct inode *inode, struct file *file)
{
struct hostaudio_state *state = file->private_data;
- int ret;
#ifdef DEBUG
printk("hostaudio: release called\n");
#endif
- ret = hostaudio_release_user(state);
+ if(state->fd >= 0){
+ os_close_file(state->fd);
+ state->fd = -1;
+ }
+
kfree(state);
- return(ret);
+ return(0);
}
/* /dev/mixer file operations */
@@ -146,7 +237,7 @@ static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file,
printk("hostmixer: ioctl called\n");
#endif
- return(hostmixer_ioctl_mixdev_user(state, cmd, arg));
+ return(os_ioctl_generic(state->fd, cmd, arg));
}
static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
@@ -165,13 +256,17 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
if(file->f_mode & FMODE_READ) r = 1;
if(file->f_mode & FMODE_WRITE) w = 1;
- ret = hostmixer_open_mixdev_user(state, r, w, mixer);
+ ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
if(ret < 0){
+ printk("hostaudio_open_mixdev failed to open '%s', err = %d\n",
+ dsp, -ret);
kfree(state);
return(ret);
}
+ state->fd = ret;
+
file->private_data = state;
return(0);
}
@@ -179,16 +274,18 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
static int hostmixer_release(struct inode *inode, struct file *file)
{
struct hostmixer_state *state = file->private_data;
- int ret;
#ifdef DEBUG
printk("hostmixer: release called\n");
#endif
- ret = hostmixer_release_mixdev_user(state);
+ if(state->fd >= 0){
+ os_close_file(state->fd);
+ state->fd = -1;
+ }
kfree(state);
- return(ret);
+ return(0);
}
@@ -225,7 +322,8 @@ MODULE_LICENSE("GPL");
static int __init hostaudio_init_module(void)
{
- printk(KERN_INFO "UML Audio Relay\n");
+ printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
+ dsp, mixer);
module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
if(module_data.dev_audio < 0){
diff --git a/arch/um/drivers/hostaudio_user.c b/arch/um/drivers/hostaudio_user.c
deleted file mode 100644
index c32fa1b0a619a..0000000000000
--- a/arch/um/drivers/hostaudio_user.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2002 Steve Schmidtke
- * Licensed under the GPL
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include "hostaudio.h"
-#include "user_util.h"
-#include "kern_util.h"
-#include "user.h"
-#include "os.h"
-
-/* /dev/dsp file operations */
-
-ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer,
- size_t count, loff_t *ppos)
-{
- ssize_t ret;
-
-#ifdef DEBUG
- printk("hostaudio: read_user called, count = %d\n", count);
-#endif
-
- ret = read(state->fd, buffer, count);
-
- if(ret < 0) return(-errno);
- return(ret);
-}
-
-ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer,
- size_t count, loff_t *ppos)
-{
- ssize_t ret;
-
-#ifdef DEBUG
- printk("hostaudio: write_user called, count = %d\n", count);
-#endif
-
- ret = write(state->fd, buffer, count);
-
- if(ret < 0) return(-errno);
- return(ret);
-}
-
-int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd,
- unsigned long arg)
-{
- int ret;
-#ifdef DEBUG
- printk("hostaudio: ioctl_user called, cmd = %u\n", cmd);
-#endif
-
- ret = ioctl(state->fd, cmd, arg);
-
- if(ret < 0) return(-errno);
- return(ret);
-}
-
-int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
-{
-#ifdef DEBUG
- printk("hostaudio: open_user called\n");
-#endif
-
- state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
-
- if(state->fd >= 0) return(0);
-
- printk("hostaudio_open_user failed to open '%s', errno = %d\n",
- dsp, errno);
-
- return(-errno);
-}
-
-int hostaudio_release_user(struct hostaudio_state *state)
-{
-#ifdef DEBUG
- printk("hostaudio: release called\n");
-#endif
- if(state->fd >= 0){
- close(state->fd);
- state->fd=-1;
- }
-
- return(0);
-}
-
-/* /dev/mixer file operations */
-
-int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state,
- unsigned int cmd, unsigned long arg)
-{
- int ret;
-#ifdef DEBUG
- printk("hostmixer: ioctl_user called cmd = %u\n",cmd);
-#endif
-
- ret = ioctl(state->fd, cmd, arg);
- if(ret < 0)
- return(-errno);
- return(ret);
-}
-
-int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
- char *mixer)
-{
-#ifdef DEBUG
- printk("hostmixer: open_user called\n");
-#endif
-
- state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
-
- if(state->fd >= 0) return(0);
-
- printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n",
- mixer, errno);
-
- return(-errno);
-}
-
-int hostmixer_release_mixdev_user(struct hostmixer_state *state)
-{
-#ifdef DEBUG
- printk("hostmixer: release_user called\n");
-#endif
-
- if(state->fd >= 0){
- close(state->fd);
- state->fd = -1;
- }
-
- 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/drivers/line.c b/arch/um/drivers/line.c
index 92efc73ca31f1..6d299b32a0a6d 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -6,8 +6,8 @@
#include "linux/sched.h"
#include "linux/slab.h"
#include "linux/list.h"
+#include "linux/interrupt.h"
#include "linux/devfs_fs_kernel.h"
-#include "asm/irq.h"
#include "asm/uaccess.h"
#include "chan_kern.h"
#include "irq_user.h"
@@ -16,38 +16,55 @@
#include "user_util.h"
#include "kern_util.h"
#include "os.h"
+#include "irq_kern.h"
#define LINE_BUFSIZE 4096
-void line_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
{
struct line *dev = data;
if(dev->count > 0)
chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq,
dev);
+ return IRQ_HANDLED;
}
-void line_timer_cb(void *arg)
+static void line_timer_cb(void *arg)
{
struct line *dev = arg;
line_interrupt(dev->driver->read_irq, dev, NULL);
}
-static void buffer_data(struct line *line, const char *buf, int len)
+static int write_room(struct line *dev)
{
- int end;
+ int n;
+
+ if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
+
+ n = dev->head - dev->tail;
+ if(n <= 0) n = LINE_BUFSIZE + n;
+ return(n - 1);
+}
+
+static int buffer_data(struct line *line, const char *buf, int len)
+{
+ int end, room;
if(line->buffer == NULL){
line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
if(line->buffer == NULL){
printk("buffer_data - atomic allocation failed\n");
- return;
+ return(0);
}
line->head = line->buffer;
line->tail = line->buffer;
}
+
+ room = write_room(line);
+ len = (len > room) ? room : len;
+
end = line->buffer + LINE_BUFSIZE - line->tail;
if(len < end){
memcpy(line->tail, buf, len);
@@ -60,6 +77,8 @@ static void buffer_data(struct line *line, const char *buf, int len)
memcpy(line->buffer, buf, len);
line->tail = line->buffer + len;
}
+
+ return(len);
}
static int flush_buffer(struct line *line)
@@ -95,7 +114,7 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user,
struct line *line;
char *new;
unsigned long flags;
- int n, err, i;
+ int n, err, i, ret = 0;
if(tty->stopped) return 0;
@@ -104,9 +123,13 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user,
if(new == NULL)
return(0);
n = copy_from_user(new, buf, len);
- if(n == len)
- return(-EFAULT);
buf = new;
+ if(n == len){
+ len = -EFAULT;
+ goto out_free;
+ }
+
+ len -= n;
}
i = tty->index;
@@ -115,41 +138,50 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user,
down(&line->sem);
if(line->head != line->tail){
local_irq_save(flags);
- buffer_data(line, buf, len);
+ ret += buffer_data(line, buf, len);
err = flush_buffer(line);
local_irq_restore(flags);
if(err <= 0)
- goto out;
+ goto out_up;
}
else {
n = write_chan(&line->chan_list, buf, len,
line->driver->write_irq);
if(n < 0){
- len = n;
- goto out;
+ ret = n;
+ goto out_up;
}
- if(n < len)
- buffer_data(line, buf + n, len - n);
+
+ len -= n;
+ ret += n;
+ if(len > 0)
+ ret += buffer_data(line, buf + n, len);
}
- out:
+ out_up:
up(&line->sem);
- return(len);
+ out_free:
+ if(from_user)
+ kfree(buf);
+ return(ret);
}
-void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t line_write_interrupt(int irq, void *data,
+ struct pt_regs *unused)
{
struct line *dev = data;
struct tty_struct *tty = dev->tty;
int err;
err = flush_buffer(dev);
- if(err == 0) return;
+ if(err == 0)
+ return(IRQ_NONE);
else if(err < 0){
dev->head = dev->buffer;
dev->tail = dev->buffer;
}
- if(tty == NULL) return;
+ if(tty == NULL)
+ return(IRQ_NONE);
if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
(tty->ldisc.write_wakeup != NULL))
@@ -161,21 +193,9 @@ void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
* writes.
*/
- if (waitqueue_active(&tty->write_wait))
+ if(waitqueue_active(&tty->write_wait))
wake_up_interruptible(&tty->write_wait);
-
-}
-
-int line_write_room(struct tty_struct *tty)
-{
- struct line *dev = tty->driver_data;
- int n;
-
- if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
-
- n = dev->head - dev->tail;
- if(n <= 0) n = LINE_BUFSIZE + n;
- return(n - 1);
+ return(IRQ_HANDLED);
}
int line_setup_irq(int fd, int input, int output, void *data)
@@ -305,7 +325,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
if(*end != '='){
printk(KERN_ERR "line_setup failed to parse \"%s\"\n",
init);
- return(1);
+ return(0);
}
init = end;
}
@@ -313,12 +333,12 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
if((n >= 0) && (n >= num)){
printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
n, num);
- return(1);
+ return(0);
}
else if(n >= 0){
if(lines[n].count > 0){
printk("line_setup - device %d is open\n", n);
- return(1);
+ return(0);
}
if(lines[n].init_pri <= INIT_ONE){
lines[n].init_pri = INIT_ONE;
@@ -332,7 +352,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
else if(!all_allowed){
printk("line_setup - can't configure all devices from "
"mconsole\n");
- return(1);
+ return(0);
}
else {
for(i = 0; i < num; i++){
@@ -346,7 +366,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed)
}
}
}
- return(0);
+ return(1);
}
int line_config(struct line *lines, int num, char *str)
@@ -357,7 +377,7 @@ int line_config(struct line *lines, int num, char *str)
printk("line_config - uml_strdup failed\n");
return(-ENOMEM);
}
- return(line_setup(lines, num, new, 0));
+ return(!line_setup(lines, num, new, 0));
}
int line_get_config(char *name, struct line *lines, int num, char *str,
@@ -369,7 +389,7 @@ int line_get_config(char *name, struct line *lines, int num, char *str,
dev = simple_strtoul(name, &end, 0);
if((*end != '\0') || (end == name)){
- *error_out = "line_setup failed to parse device number";
+ *error_out = "line_get_config failed to parse device number";
return(0);
}
@@ -379,15 +399,15 @@ int line_get_config(char *name, struct line *lines, int num, char *str,
}
line = &lines[dev];
+
down(&line->sem);
-
if(!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1);
else if(line->count == 0)
CONFIG_CHUNK(str, size, n, line->init_str, 1);
else n = chan_config_string(&line->chan_list, str, size, error_out);
-
up(&line->sem);
+
return(n);
}
@@ -396,7 +416,14 @@ int line_remove(struct line *lines, int num, char *str)
char config[sizeof("conxxxx=none\0")];
sprintf(config, "%s=none", str);
- return(line_setup(lines, num, config, 0));
+ return(!line_setup(lines, num, config, 0));
+}
+
+int line_write_room(struct tty_struct *tty)
+{
+ struct line *dev = tty->driver_data;
+
+ return(write_room(dev));
}
struct tty_driver *line_register_devfs(struct lines *set,
@@ -412,7 +439,8 @@ struct tty_driver *line_register_devfs(struct lines *set,
return NULL;
driver->driver_name = line_driver->name;
- driver->name = line_driver->devfs_name;
+ driver->name = line_driver->device_name;
+ driver->devfs_name = line_driver->devfs_name;
driver->major = line_driver->major;
driver->minor_start = line_driver->minor_start;
driver->type = line_driver->type;
@@ -432,7 +460,7 @@ struct tty_driver *line_register_devfs(struct lines *set,
for(i = 0; i < nlines; i++){
if(!lines[i].valid)
- tty_unregister_devfs(driver, i);
+ tty_unregister_device(driver, i);
}
mconsole_register_dev(&line_driver->mc);
@@ -465,24 +493,25 @@ struct winch {
struct line *line;
};
-void winch_interrupt(int irq, void *data, struct pt_regs *unused)
+irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
{
struct winch *winch = data;
struct tty_struct *tty;
int err;
char c;
- err = generic_read(winch->fd, &c, NULL);
- if(err < 0){
- if(err != -EAGAIN){
- printk("winch_interrupt : read failed, errno = %d\n",
- -err);
- printk("fd %d is losing SIGWINCH support\n",
- winch->tty_fd);
- free_irq(irq, data);
- return;
+ if(winch->fd != -1){
+ err = generic_read(winch->fd, &c, NULL);
+ if(err < 0){
+ if(err != -EAGAIN){
+ printk("winch_interrupt : read failed, "
+ "errno = %d\n", -err);
+ printk("fd %d is losing SIGWINCH support\n",
+ winch->tty_fd);
+ return(IRQ_HANDLED);
+ }
+ goto out;
}
- goto out;
}
tty = winch->line->tty;
if(tty != NULL){
@@ -492,7 +521,9 @@ void winch_interrupt(int irq, void *data, struct pt_regs *unused)
kill_pg(tty->pgrp, SIGWINCH, 1);
}
out:
- reactivate_fd(winch->fd, WINCH_IRQ);
+ if(winch->fd != -1)
+ reactivate_fd(winch->fd, WINCH_IRQ);
+ return(IRQ_HANDLED);
}
DECLARE_MUTEX(winch_handler_sem);
@@ -529,7 +560,10 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
- close(winch->fd);
+ if(winch->fd != -1){
+ deactivate_fd(winch->fd, WINCH_IRQ);
+ os_close_file(winch->fd);
+ }
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
}
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index 58e5db6304615..0fe1d9fa9139a 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -23,6 +23,7 @@
#include "kern_util.h"
#include "user_util.h"
#include "user.h"
+#include "os.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
@@ -62,7 +63,8 @@ static int mcast_open(void *data)
goto out;
}
- if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0){
printk("mcast_open : data socket failed, errno = %d\n",
errno);
fd = -ENOMEM;
@@ -72,7 +74,7 @@ static int mcast_open(void *data)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
errno);
- close(fd);
+ os_close_file(fd);
fd = -EINVAL;
goto out;
}
@@ -82,7 +84,7 @@ static int mcast_open(void *data)
sizeof(pri->ttl)) < 0) {
printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
errno);
- close(fd);
+ os_close_file(fd);
fd = -EINVAL;
goto out;
}
@@ -91,7 +93,7 @@ static int mcast_open(void *data)
if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
errno);
- close(fd);
+ os_close_file(fd);
fd = -EINVAL;
goto out;
}
@@ -99,7 +101,7 @@ static int mcast_open(void *data)
/* bind socket to mcast address */
if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
printk("mcast_open : data bind failed, errno = %d\n", errno);
- close(fd);
+ os_close_file(fd);
fd = -EINVAL;
goto out;
}
@@ -115,7 +117,7 @@ static int mcast_open(void *data)
"interface on the host.\n");
printk("eth0 should be configured in order to use the "
"multicast transport.\n");
- close(fd);
+ os_close_file(fd);
fd = -EINVAL;
}
@@ -137,7 +139,7 @@ static void mcast_close(int fd, void *data)
errno);
}
- close(fd);
+ os_close_file(fd);
}
int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index b12cb189d1e4c..badcbb4f45458 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -15,6 +15,9 @@
#include "linux/sysrq.h"
#include "linux/workqueue.h"
#include "linux/module.h"
+#include "linux/file.h"
+#include "linux/fs.h"
+#include "linux/namei.h"
#include "linux/proc_fs.h"
#include "asm/irq.h"
#include "asm/uaccess.h"
@@ -27,6 +30,7 @@
#include "init.h"
#include "os.h"
#include "umid.h"
+#include "irq_kern.h"
static int do_unlink_socket(struct notifier_block *notifier,
unsigned long what, void *data)
@@ -67,7 +71,7 @@ void mc_work_proc(void *unused)
DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
-void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int fd;
struct mconsole_entry *new;
@@ -75,9 +79,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
fd = (int) dev_id;
while (mconsole_get_request(fd, &req)){
- if(req.cmd->as_interrupt) (*req.cmd->handler)(&req);
+ if(req.cmd->context == MCONSOLE_INTR)
+ (*req.cmd->handler)(&req);
else {
- new = kmalloc(sizeof(req), GFP_ATOMIC);
+ new = kmalloc(sizeof(*new), GFP_ATOMIC);
if(new == NULL)
mconsole_reply(&req, "Out of memory", 1, 0);
else {
@@ -88,6 +93,7 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
reactivate_fd(fd, MCONSOLE_IRQ);
+ return(IRQ_HANDLED);
}
void mconsole_version(struct mc_request *req)
@@ -100,20 +106,109 @@ void mconsole_version(struct mc_request *req)
mconsole_reply(req, version, 0, 0);
}
+void mconsole_log(struct mc_request *req)
+{
+ int len;
+ char *ptr = req->request.data;
+
+ ptr += strlen("log ");
+
+ len = req->len - (ptr - req->request.data);
+ printk("%.*s", len, ptr);
+ mconsole_reply(req, "", 0, 0);
+}
+
+void mconsole_proc(struct mc_request *req)
+{
+ struct nameidata nd;
+ struct file_system_type *proc;
+ struct super_block *super;
+ struct file *file;
+ int n, err;
+ char *ptr = req->request.data, *buf;
+
+ ptr += strlen("proc");
+ while(isspace(*ptr)) ptr++;
+
+ proc = get_fs_type("proc");
+ if(proc == NULL){
+ mconsole_reply(req, "procfs not registered", 1, 0);
+ goto out;
+ }
+
+ super = (*proc->get_sb)(proc, 0, NULL, NULL);
+ put_filesystem(proc);
+ if(super == NULL){
+ mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
+ goto out;
+ }
+ up_write(&super->s_umount);
+
+ nd.dentry = super->s_root;
+ nd.mnt = NULL;
+ nd.flags = O_RDONLY + 1;
+ nd.last_type = LAST_ROOT;
+
+ err = link_path_walk(ptr, &nd);
+ if(err){
+ mconsole_reply(req, "Failed to look up file", 1, 0);
+ goto out_kill;
+ }
+
+ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+ if(IS_ERR(file)){
+ mconsole_reply(req, "Failed to open file", 1, 0);
+ goto out_kill;
+ }
+
+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if(buf == NULL){
+ mconsole_reply(req, "Failed to allocate buffer", 1, 0);
+ goto out_fput;
+ }
+
+ if((file->f_op != NULL) && (file->f_op->read != NULL)){
+ do {
+ n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
+ &file->f_pos);
+ if(n >= 0){
+ buf[n] = '\0';
+ mconsole_reply(req, buf, 0, (n > 0));
+ }
+ else {
+ mconsole_reply(req, "Read of file failed",
+ 1, 0);
+ goto out_free;
+ }
+ } while(n > 0);
+ }
+ else mconsole_reply(req, "", 0, 0);
+
+ out_free:
+ kfree(buf);
+ out_fput:
+ fput(file);
+ out_kill:
+ deactivate_super(super);
+ out: ;
+}
+
#define UML_MCONSOLE_HELPTEXT \
-"Commands:
- version - Get kernel version
- help - Print this message
- halt - Halt UML
- reboot - Reboot UML
- config <dev>=<config> - Add a new device to UML;
- same syntax as command line
- config <dev> - Query the configuration of a device
- remove <dev> - Remove a device from UML
- sysrq <letter> - Performs the SysRq action controlled by the letter
- cad - invoke the Ctl-Alt-Del handler
- stop - pause the UML; it will do nothing until it receives a 'go'
- go - continue the UML after a 'stop'
+"Commands: \n\
+ version - Get kernel version \n\
+ help - Print this message \n\
+ halt - Halt UML \n\
+ reboot - Reboot UML \n\
+ config <dev>=<config> - Add a new device to UML; \n\
+ same syntax as command line \n\
+ config <dev> - Query the configuration of a device \n\
+ remove <dev> - Remove a device from UML \n\
+ sysrq <letter> - Performs the SysRq action controlled by the letter \n\
+ cad - invoke the Ctl-Alt-Del handler \n\
+ stop - pause the UML; it will do nothing until it receives a 'go' \n\
+ go - continue the UML after a 'stop' \n\
+ log <string> - make UML enter <string> into the kernel log\n\
+ proc <file> - returns the contents of the UML's /proc/<file>\n\
"
void mconsole_help(struct mc_request *req)
@@ -302,7 +397,7 @@ int mconsole_init(void)
if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
snprintf(mconsole_socket_name, sizeof(file), "%s", file);
- sock = create_unix_socket(file, sizeof(file));
+ sock = os_create_unix_socket(file, sizeof(file), 1);
if (sock < 0){
printk("Failed to initialize management console\n");
return(1);
@@ -344,11 +439,16 @@ static int write_proc_mconsole(struct file *file, const char *buffer,
if(buf == NULL)
return(-ENOMEM);
- if(copy_from_user(buf, buffer, count))
- return(-EFAULT);
+ if(copy_from_user(buf, buffer, count)){
+ count = -EFAULT;
+ goto out;
+ }
+
buf[count] = '\0';
mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
+ out:
+ kfree(buf);
return(count);
}
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 11b09a96f4545..fe5afb13252c8 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -18,16 +18,18 @@
#include "umid.h"
static struct mconsole_command commands[] = {
- { "version", mconsole_version, 1 },
- { "halt", mconsole_halt, 0 },
- { "reboot", mconsole_reboot, 0 },
- { "config", mconsole_config, 0 },
- { "remove", mconsole_remove, 0 },
- { "sysrq", mconsole_sysrq, 1 },
- { "help", mconsole_help, 1 },
- { "cad", mconsole_cad, 1 },
- { "stop", mconsole_stop, 0 },
- { "go", mconsole_go, 1 },
+ { "version", mconsole_version, MCONSOLE_INTR },
+ { "halt", mconsole_halt, MCONSOLE_PROC },
+ { "reboot", mconsole_reboot, MCONSOLE_PROC },
+ { "config", mconsole_config, MCONSOLE_PROC },
+ { "remove", mconsole_remove, MCONSOLE_PROC },
+ { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
+ { "help", mconsole_help, MCONSOLE_INTR },
+ { "cad", mconsole_cad, MCONSOLE_INTR },
+ { "stop", mconsole_stop, MCONSOLE_PROC },
+ { "go", mconsole_go, MCONSOLE_INTR },
+ { "log", mconsole_log, MCONSOLE_INTR },
+ { "proc", mconsole_proc, MCONSOLE_PROC },
};
/* Initialized in mconsole_init, which is an initcall */
@@ -139,6 +141,7 @@ int mconsole_reply(struct mc_request *req, char *str, int err, int more)
memcpy(reply.data, str, len);
reply.data[len] = '\0';
total -= len;
+ str += len;
reply.len = len + 1;
len = sizeof(reply) + reply.len - sizeof(reply.data);
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index 628d8f80434e6..1862691b91469 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -120,7 +120,10 @@ static int __init mmapper_init(void)
printk(KERN_INFO "Mapper v0.1\n");
v_buf = (char *) find_iomem("mmapper", &mmapper_size);
- if(mmapper_size == 0) return(0);
+ if(mmapper_size == 0){
+ printk(KERN_ERR "mmapper_init - find_iomem failed\n");
+ return(0);
+ }
p_buf = __pa(v_buf);
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index a52b79dfd5ba1..e3108114af901 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -26,6 +26,7 @@
#include "mconsole_kern.h"
#include "init.h"
#include "irq_user.h"
+#include "irq_kern.h"
static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
LIST_HEAD(opened);
@@ -37,7 +38,8 @@ static int uml_net_rx(struct net_device *dev)
struct sk_buff *skb;
/* If we can't allocate memory, try again next round. */
- if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
+ skb = dev_alloc_skb(dev->mtu);
+ if (skb == NULL) {
lp->stats.rx_dropped++;
return 0;
}
@@ -61,14 +63,14 @@ static int uml_net_rx(struct net_device *dev)
return pkt_len;
}
-void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct uml_net_private *lp = dev->priv;
int err;
if(!netif_running(dev))
- return;
+ return(IRQ_NONE);
spin_lock(&lp->lock);
while((err = uml_net_rx(dev)) > 0) ;
@@ -83,6 +85,7 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
out:
spin_unlock(&lp->lock);
+ return(IRQ_HANDLED);
}
static int uml_net_open(struct net_device *dev)
@@ -250,37 +253,6 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
-/*
- * default do nothing hard header packet routines for struct net_device init.
- * real ethernet transports will overwrite with real routines.
- */
-static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
-{
- return(0); /* no change */
-}
-
-static int uml_net_rebuild_header(struct sk_buff *skb)
-{
- return(0); /* ignore */
-}
-
-static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
-{
- return(-1); /* fail */
-}
-
-static void uml_net_header_cache_update(struct hh_cache *hh,
- struct net_device *dev, unsigned char * haddr)
-{
- /* ignore */
-}
-
-static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
-{
- return(0); /* nothing */
-}
-
static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
static struct list_head devices = LIST_HEAD_INIT(devices);
@@ -290,7 +262,7 @@ static int eth_configure(int n, void *init, char *mac,
struct uml_net *device;
struct net_device *dev;
struct uml_net_private *lp;
- int err, size;
+ int save, err, size;
size = transport->private_size + sizeof(struct uml_net_private) +
sizeof(((struct uml_net_private *) 0)->user);
@@ -332,12 +304,6 @@ static int eth_configure(int n, void *init, char *mac,
snprintf(dev->name, sizeof(dev->name), "eth%d", n);
device->dev = dev;
- dev->hard_header = uml_net_hard_header;
- dev->rebuild_header = uml_net_rebuild_header;
- dev->hard_header_cache = uml_net_header_cache;
- dev->header_cache_update= uml_net_header_cache_update;
- dev->hard_header_parse = uml_net_header_parse;
-
(*transport->kern->init)(dev, init);
dev->mtu = transport->user->max_packet;
@@ -364,21 +330,29 @@ static int eth_configure(int n, void *init, char *mac,
}
lp = dev->priv;
- INIT_LIST_HEAD(&lp->list);
- spin_lock_init(&lp->lock);
- lp->dev = dev;
- lp->fd = -1;
- lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 };
- lp->have_mac = device->have_mac;
- lp->protocol = transport->kern->protocol;
- lp->open = transport->user->open;
- lp->close = transport->user->close;
- lp->remove = transport->user->remove;
- lp->read = transport->kern->read;
- lp->write = transport->kern->write;
- lp->add_address = transport->user->add_address;
- lp->delete_address = transport->user->delete_address;
- lp->set_mtu = transport->user->set_mtu;
+ /* lp.user is the first four bytes of the transport data, which
+ * has already been initialized. This structure assignment will
+ * overwrite that, so we make sure that .user gets overwritten with
+ * what it already has.
+ */
+ save = lp->user[0];
+ *lp = ((struct uml_net_private)
+ { .list = LIST_HEAD_INIT(lp->list),
+ .lock = SPIN_LOCK_UNLOCKED,
+ .dev = dev,
+ .fd = -1,
+ .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
+ .have_mac = device->have_mac,
+ .protocol = transport->kern->protocol,
+ .open = transport->user->open,
+ .close = transport->user->close,
+ .remove = transport->user->remove,
+ .read = transport->kern->read,
+ .write = transport->kern->write,
+ .add_address = transport->user->add_address,
+ .delete_address = transport->user->delete_address,
+ .set_mtu = transport->user->set_mtu,
+ .user = { save } });
init_timer(&lp->tl);
lp->tl.function = uml_net_user_timer_expire;
@@ -611,7 +585,8 @@ static int net_remove(char *str)
unregister_netdev(dev);
list_del(&device->list);
- free_netdev(device);
+ kfree(device);
+ free_netdev(dev);
return(0);
}
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 75a83e9e12037..2e4e1d49f00b9 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -26,8 +26,7 @@ int tap_open_common(void *dev, char *gate_addr)
if(gate_addr == NULL) return(0);
if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0],
&tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
- printk("Invalid tap IP address - '%s'\n",
- gate_addr);
+ printk("Invalid tap IP address - '%s'\n", gate_addr);
return(-EINVAL);
}
return(0);
@@ -60,18 +59,18 @@ void read_output(int fd, char *output, int len)
}
*output = '\0';
- if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){
- printk("read_output - read of length failed, errno = %d\n",
- errno);
+ n = os_read_file(fd, &remain, sizeof(remain));
+ if(n != sizeof(remain)){
+ printk("read_output - read of length failed, err = %d\n", -n);
return;
}
while(remain != 0){
n = (remain < len) ? remain : len;
- actual = read(fd, output, n);
+ actual = os_read_file(fd, output, n);
if(actual != n){
printk("read_output - read of data failed, "
- "errno = %d\n", errno);
+ "err = %d\n", -actual);
return;
}
remain -= actual;
@@ -83,13 +82,12 @@ int net_read(int fd, void *buf, int len)
{
int n;
- while(((n = read(fd, buf, len)) < 0) && (errno == EINTR)) ;
+ n = os_read_file(fd, buf, len);
- if(n < 0){
- if(errno == EAGAIN) return(0);
- return(-errno);
- }
- else if(n == 0) return(-ENOTCONN);
+ if(n == -EAGAIN)
+ return(0);
+ else if(n == 0)
+ return(-ENOTCONN);
return(n);
}
@@ -112,13 +110,13 @@ int net_write(int fd, void *buf, int len)
{
int n;
- while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ;
- if(n < 0){
- if(errno == EAGAIN) return(0);
- return(-errno);
- }
- else if(n == 0) return(-ENOTCONN);
- return(n);
+ n = os_write_file(fd, buf, len);
+
+ if(n == -EAGAIN)
+ return(0);
+ else if(n == 0)
+ return(-ENOTCONN);
+ return(n);
}
int net_send(int fd, void *buf, int len)
@@ -157,7 +155,7 @@ static void change_pre_exec(void *arg)
{
struct change_pre_exec_data *data = arg;
- close(data->close_me);
+ os_close_file(data->close_me);
dup2(data->stdout, 1);
}
@@ -167,17 +165,18 @@ static int change_tramp(char **argv, char *output, int output_len)
struct change_pre_exec_data pe_data;
err = os_pipe(fds, 1, 0);
- if(err){
- printk("change_tramp - pipe failed, errno = %d\n", -err);
+ if(err < 0){
+ printk("change_tramp - pipe failed, err = %d\n", -err);
return(err);
}
pe_data.close_me = fds[0];
pe_data.stdout = fds[1];
pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
- close(fds[1]);
+ os_close_file(fds[1]);
read_output(fds[0], output, output_len);
- waitpid(pid, NULL, 0);
+
+ CATCH_EINTR(err = waitpid(pid, NULL, 0));
return(pid);
}
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
index d361554ebd9a6..66b2fbe3dfb2e 100644
--- a/arch/um/drivers/null.c
+++ b/arch/um/drivers/null.c
@@ -5,7 +5,6 @@
#include <stdlib.h>
#include <errno.h>
-#include <fcntl.h>
#include "chan_user.h"
#include "os.h"
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index 3c44630191c43..4044053cd9e36 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -6,6 +6,7 @@
#include "linux/list.h"
#include "linux/sched.h"
#include "linux/slab.h"
+#include "linux/interrupt.h"
#include "linux/irq.h"
#include "linux/spinlock.h"
#include "linux/errno.h"
@@ -14,6 +15,7 @@
#include "kern_util.h"
#include "kern.h"
#include "irq_user.h"
+#include "irq_kern.h"
#include "port.h"
#include "init.h"
#include "os.h"
@@ -38,21 +40,21 @@ struct port_dev {
struct connection {
struct list_head list;
int fd;
- int helper_pid;
+ int helper_pid;
int socket[2];
int telnetd_pid;
struct port_list *port;
};
-static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
{
struct connection *conn = data;
int fd;
- fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
+ fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
if(fd < 0){
if(fd == -EAGAIN)
- return;
+ return(IRQ_NONE);
printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
-fd);
@@ -65,6 +67,7 @@ static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
list_add(&conn->list, &conn->port->connections);
up(&conn->port->sem);
+ return(IRQ_HANDLED);
}
static int port_accept(struct port_list *port)
@@ -102,8 +105,7 @@ static int port_accept(struct port_list *port)
}
list_add(&conn->list, &port->pending);
- ret = 1;
- goto out;
+ return(1);
out_free:
kfree(conn);
@@ -138,12 +140,13 @@ void port_work_proc(void *unused)
DECLARE_WORK(port_work, port_work_proc, NULL);
-static void port_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
{
struct port_list *port = data;
port->has_connection = 1;
schedule_work(&port_work);
+ return(IRQ_HANDLED);
}
void *port_data(int port_num)
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index 7a37cf6a24a57..e0588cbe3720a 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -47,10 +47,12 @@ void *port_init(char *str, int device, struct chan_opts *opts)
return(NULL);
}
- if((kern_data = port_data(port)) == NULL)
+ kern_data = port_data(port);
+ if(kern_data == NULL)
return(NULL);
- if((data = um_kmalloc(sizeof(*data))) == NULL)
+ data = um_kmalloc(sizeof(*data));
+ if(data == NULL)
goto err;
*data = ((struct port_chan) { .raw = opts->raw,
@@ -90,7 +92,7 @@ void port_close(int fd, void *d)
struct port_chan *data = d;
port_remove_dev(data->kernel_data);
- close(fd);
+ os_close_file(fd);
}
int port_console_write(int fd, const char *buf, int n, void *d)
@@ -130,11 +132,15 @@ int port_listen_fd(int port)
goto out;
}
- if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){
+ if(listen(fd, 1) < 0){
err = -errno;
goto out;
}
+ err = os_set_fd_block(fd, 0);
+ if(err < 0)
+ goto out;
+
return(fd);
out:
os_close_file(fd);
@@ -153,10 +159,10 @@ void port_pre_exec(void *arg)
dup2(data->sock_fd, 0);
dup2(data->sock_fd, 1);
dup2(data->sock_fd, 2);
- close(data->sock_fd);
+ os_close_file(data->sock_fd);
dup2(data->pipe_fd, 3);
os_shutdown_socket(3, 1, 0);
- close(data->pipe_fd);
+ os_close_file(data->pipe_fd);
}
int port_connection(int fd, int *socket, int *pid_out)
@@ -166,11 +172,12 @@ int port_connection(int fd, int *socket, int *pid_out)
"/usr/lib/uml/port-helper", NULL };
struct port_pre_exec_data data;
- if((new = os_accept_connection(fd)) < 0)
- return(-errno);
+ new = os_accept_connection(fd);
+ if(new < 0)
+ return(new);
err = os_pipe(socket, 0, 0);
- if(err)
+ if(err < 0)
goto out_close;
data = ((struct port_pre_exec_data)
@@ -186,11 +193,11 @@ int port_connection(int fd, int *socket, int *pid_out)
out_shutdown:
os_shutdown_socket(socket[0], 1, 1);
- close(socket[0]);
+ os_close_file(socket[0]);
os_shutdown_socket(socket[1], 1, 1);
- close(socket[1]);
+ os_close_file(socket[1]);
out_close:
- close(new);
+ os_close_file(new);
return(err);
}
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 0274053866b8c..bfa08d8126046 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -7,12 +7,12 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <fcntl.h>
#include <termios.h>
#include "chan_user.h"
#include "user.h"
#include "user_util.h"
#include "kern_util.h"
+#include "os.h"
struct pty_chan {
void (*announce)(char *dev_name, int dev);
@@ -26,7 +26,8 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts)
{
struct pty_chan *data;
- if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+ data = um_kmalloc(sizeof(*data));
+ if(data == NULL) return(NULL);
*data = ((struct pty_chan) { .announce = opts->announce,
.dev = device,
.raw = opts->raw });
@@ -39,7 +40,8 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out)
char *dev;
int fd;
- if((fd = get_pty()) < 0){
+ fd = get_pty();
+ if(fd < 0){
printk("open_pts : Failed to open pts\n");
return(-errno);
}
@@ -57,29 +59,27 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out)
int getmaster(char *line)
{
- struct stat stb;
char *pty, *bank, *cp;
- int master;
+ int master, err;
pty = &line[strlen("/dev/ptyp")];
for (bank = "pqrs"; *bank; bank++) {
line[strlen("/dev/pty")] = *bank;
*pty = '0';
- if (stat(line, &stb) < 0)
+ if (os_stat_file(line, NULL) < 0)
break;
for (cp = "0123456789abcdef"; *cp; cp++) {
*pty = *cp;
- master = open(line, O_RDWR);
+ master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
if (master >= 0) {
char *tp = &line[strlen("/dev/")];
- int ok;
/* verify slave side is usable */
*tp = 't';
- ok = access(line, R_OK|W_OK) == 0;
+ err = os_access(line, OS_ACC_RW_OK);
*tp = 'p';
- if (ok) return(master);
- (void) close(master);
+ if(err == 0) return(master);
+ (void) os_close_file(master);
}
}
}
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 782cf522bb42d..3d8d4ca360215 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -4,11 +4,9 @@
#include <stddef.h>
#include <sched.h>
#include <string.h>
-#include <sys/fcntl.h>
-#include <sys/errno.h>
+#include <errno.h>
#include <sys/termios.h>
#include <sys/wait.h>
-#include <sys/ioctl.h>
#include <sys/signal.h>
#include "user_util.h"
#include "kern_util.h"
@@ -65,9 +63,9 @@ static void slip_pre_exec(void *arg)
{
struct slip_pre_exec_data *data = arg;
- if(data->stdin != -1) dup2(data->stdin, 0);
+ if(data->stdin >= 0) dup2(data->stdin, 0);
dup2(data->stdout, 1);
- if(data->close_me != -1) close(data->close_me);
+ if(data->close_me >= 0) os_close_file(data->close_me);
}
static int slip_tramp(char **argv, int fd)
@@ -77,8 +75,8 @@ static int slip_tramp(char **argv, int fd)
int status, pid, fds[2], err, output_len;
err = os_pipe(fds, 1, 0);
- if(err){
- printk("slip_tramp : pipe failed, errno = %d\n", -err);
+ if(err < 0){
+ printk("slip_tramp : pipe failed, err = %d\n", -err);
return(err);
}
@@ -96,16 +94,18 @@ static int slip_tramp(char **argv, int fd)
printk("slip_tramp : failed to allocate output "
"buffer\n");
- close(fds[1]);
+ os_close_file(fds[1]);
read_output(fds[0], output, output_len);
if(output != NULL){
printk("%s", output);
kfree(output);
}
- if(waitpid(pid, &status, 0) < 0) err = errno;
+ CATCH_EINTR(err = waitpid(pid, &status, 0));
+ if(err < 0)
+ err = errno;
else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
printk("'%s' didn't exit with status 0\n", argv[0]);
- err = EINVAL;
+ err = -EINVAL;
}
}
return(err);
@@ -118,15 +118,17 @@ static int slip_open(void *data)
char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
NULL };
- int sfd, mfd, disc, sencap, err;
+ int sfd, mfd, err;
- if((mfd = get_pty()) < 0){
- printk("umn : Failed to open pty\n");
- return(-1);
+ mfd = get_pty();
+ if(mfd < 0){
+ printk("umn : Failed to open pty, err = %d\n", -mfd);
+ return(mfd);
}
- if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){
- printk("Couldn't open tty for slip line\n");
- return(-1);
+ sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
+ if(sfd < 0){
+ printk("Couldn't open tty for slip line, err = %d\n", -sfd);
+ return(sfd);
}
if(set_up_tty(sfd)) return(-1);
pri->slave = sfd;
@@ -138,28 +140,23 @@ static int slip_open(void *data)
err = slip_tramp(argv, sfd);
- if(err != 0){
- printk("slip_tramp failed - errno = %d\n", err);
- return(-err);
+ if(err < 0){
+ printk("slip_tramp failed - err = %d\n", -err);
+ return(err);
}
- if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){
- printk("SIOCGIFNAME failed, errno = %d\n", errno);
- return(-errno);
+ err = os_get_ifname(pri->slave, pri->name);
+ if(err < 0){
+ printk("get_ifname failed, err = %d\n", -err);
+ return(err);
}
iter_addresses(pri->dev, open_addr, pri->name);
}
else {
- disc = N_SLIP;
- if(ioctl(sfd, TIOCSETD, &disc) < 0){
- printk("Failed to set slip line discipline - "
- "errno = %d\n", errno);
- return(-errno);
- }
- sencap = 0;
- if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
- printk("Failed to set slip encapsulation - "
- "errno = %d\n", errno);
- return(-errno);
+ err = os_set_slip(sfd);
+ if(err < 0){
+ printk("Failed to set slip discipline encapsulation - "
+ "err = %d\n", -err);
+ return(err);
}
}
return(mfd);
@@ -181,9 +178,9 @@ static void slip_close(int fd, void *data)
err = slip_tramp(argv, -1);
if(err != 0)
- printk("slip_tramp failed - errno = %d\n", err);
- close(fd);
- close(pri->slave);
+ printk("slip_tramp failed - errno = %d\n", -err);
+ os_close_file(fd);
+ os_close_file(pri->slave);
pri->slave = -1;
}
@@ -243,7 +240,7 @@ static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
{
struct slip_data *pri = data;
- if(pri->slave == -1) return;
+ if(pri->slave < 0) return;
open_addr(addr, netmask, pri->name);
}
@@ -252,7 +249,7 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
{
struct slip_data *pri = data;
- if(pri->slave == -1) return;
+ if(pri->slave < 0) return;
close_addr(addr, netmask, pri->name);
}
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index cbdbb65c3ef08..c322515c71ccb 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -4,8 +4,7 @@
#include <stddef.h>
#include <sched.h>
#include <string.h>
-#include <sys/fcntl.h>
-#include <sys/errno.h>
+#include <errno.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include "user_util.h"
@@ -48,15 +47,15 @@ static int slirp_tramp(char **argv, int fd)
return(pid);
}
-
+
+/* XXX This is just a trivial wrapper around os_pipe */
static int slirp_datachan(int *mfd, int *sfd)
{
int fds[2], err;
err = os_pipe(fds, 1, 1);
- if(err){
- printk("slirp_datachan: Failed to open pipe, errno = %d\n",
- -err);
+ if(err < 0){
+ printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
return(err);
}
@@ -77,7 +76,7 @@ static int slirp_open(void *data)
pid = slirp_tramp(pri->argw.argv, sfd);
if(pid < 0){
- printk("slirp_tramp failed - errno = %d\n", pid);
+ printk("slirp_tramp failed - errno = %d\n", -pid);
os_close_file(sfd);
os_close_file(mfd);
return(pid);
@@ -97,8 +96,8 @@ static void slirp_close(int fd, void *data)
struct slirp_data *pri = data;
int status,err;
- close(fd);
- close(pri->slave);
+ os_close_file(fd);
+ os_close_file(pri->slave);
pri->slave = -1;
@@ -114,13 +113,13 @@ static void slirp_close(int fd, void *data)
}
#endif
- err = waitpid(pri->pid, &status, WNOHANG);
- if(err<0) {
+ CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
+ if(err < 0) {
printk("slirp_close: waitpid returned %d\n", errno);
return;
}
- if(err==0) {
+ if(err == 0) {
printk("slirp_close: process %d has not exited\n");
return;
}
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 826a77c8c80a3..4a3586f0dd2cc 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -10,6 +10,7 @@
#include "linux/major.h"
#include "linux/mm.h"
#include "linux/init.h"
+#include "linux/console.h"
#include "asm/termbits.h"
#include "asm/irq.h"
#include "line.h"
@@ -53,8 +54,9 @@ static int ssl_remove(char *str);
static struct line_driver driver = {
.name = "UML serial line",
- .devfs_name = "tts/%d",
- .major = TTYAUX_MAJOR,
+ .device_name = "ttS",
+ .devfs_name = "tts/",
+ .major = TTY_MAJOR,
.minor_start = 64,
.type = TTY_DRIVER_TYPE_SERIAL,
.subtype = 0,
@@ -149,6 +151,9 @@ static int ssl_ioctl(struct tty_struct *tty, struct file * file,
case TCSETSW:
case TCGETA:
case TIOCMGET:
+ case TCSBRK:
+ case TCSBRKP:
+ case TIOCMSET:
ret = -ENOIOCTLCMD;
break;
default:
@@ -212,6 +217,37 @@ static struct tty_operations ssl_ops = {
*/
static int ssl_init_done = 0;
+static void ssl_console_write(struct console *c, const char *string,
+ unsigned len)
+{
+ struct line *line = &serial_lines[c->index];
+ if(ssl_init_done)
+ down(&line->sem);
+ console_write_chan(&line->chan_list, string, len);
+ if(ssl_init_done)
+ up(&line->sem);
+}
+
+static struct tty_driver *ssl_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return ssl_driver;
+}
+
+static int ssl_console_setup(struct console *co, char *options)
+{
+ return(0);
+}
+
+static struct console ssl_cons = {
+ name: "ttyS",
+ write: ssl_console_write,
+ device: ssl_console_device,
+ setup: ssl_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
int ssl_init(void)
{
char *new_title;
@@ -227,17 +263,18 @@ int ssl_init(void)
new_title = add_xterm_umid(opts.xterm_title);
if(new_title != NULL) opts.xterm_title = new_title;
+ register_console(&ssl_cons);
ssl_init_done = 1;
return(0);
}
-__initcall(ssl_init);
+late_initcall(ssl_init);
static int ssl_chan_setup(char *str)
{
- line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
- str, 1);
- return(1);
+ return(line_setup(serial_lines,
+ sizeof(serial_lines)/sizeof(serial_lines[0]),
+ str, 1));
}
__setup("ssl", ssl_chan_setup);
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 3ae795edfe8bc..5fdc50db6f0a9 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -83,7 +83,8 @@ static int con_remove(char *str);
static struct line_driver driver = {
.name = "UML console",
- .devfs_name = "vc/%d",
+ .device_name = "tty",
+ .devfs_name = "vc/",
.major = TTY_MAJOR,
.minor_start = 0,
.type = TTY_DRIVER_TYPE_CONSOLE,
@@ -159,6 +160,15 @@ static int chars_in_buffer(struct tty_struct *tty)
static int con_init_done = 0;
+static struct tty_operations console_ops = {
+ .open = con_open,
+ .close = con_close,
+ .write = con_write,
+ .chars_in_buffer = chars_in_buffer,
+ .set_termios = set_termios,
+ .write_room = line_write_room,
+};
+
int stdio_init(void)
{
char *new_title;
@@ -166,7 +176,8 @@ int stdio_init(void)
printk(KERN_INFO "Initializing stdio console driver\n");
console_driver = line_register_devfs(&console_lines, &driver,
- &console_ops, vts, sizeof(vts)/sizeof(vts[0]));
+ &console_ops, vts,
+ sizeof(vts)/sizeof(vts[0]));
lines_init(vts, sizeof(vts)/sizeof(vts[0]));
@@ -178,26 +189,21 @@ int stdio_init(void)
return(0);
}
-__initcall(stdio_init);
+late_initcall(stdio_init);
static void console_write(struct console *console, const char *string,
unsigned len)
{
- if(con_init_done) down(&vts[console->index].sem);
- console_write_chan(&vts[console->index].chan_list, string, len);
- if(con_init_done) up(&vts[console->index].sem);
-}
+ struct line *line = &vts[console->index];
-static struct tty_operations console_ops = {
- .open = con_open,
- .close = con_close,
- .write = con_write,
- .chars_in_buffer = chars_in_buffer,
- .set_termios = set_termios,
- .write_room = line_write_room,
-};
+ if(con_init_done)
+ down(&line->sem);
+ console_write_chan(&line->chan_list, string, len);
+ if(con_init_done)
+ up(&line->sem);
+}
-static struct tty_driver *console_device(struct console *c, int *index)
+static struct tty_driver *um_console_device(struct console *c, int *index)
{
*index = c->index;
return console_driver;
@@ -208,22 +214,28 @@ static int console_setup(struct console *co, char *options)
return(0);
}
-static struct console stdiocons = INIT_CONSOLE("tty", console_write,
- console_device, console_setup,
- CON_PRINTBUFFER);
+static struct console stdiocons = {
+ name: "tty",
+ write: console_write,
+ device: um_console_device,
+ setup: console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
-static void __init stdio_console_init(void)
+static int __init stdio_console_init(void)
{
INIT_LIST_HEAD(&vts[0].chan_list);
list_add(&init_console_chan.list, &vts[0].chan_list);
register_console(&stdiocons);
+ return(0);
}
+
console_initcall(stdio_console_init);
static int console_chan_setup(char *str)
{
- line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1);
- return(1);
+ return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
}
__setup("con", console_chan_setup);
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index e9eb9e3622c4f..20a7e45a9ebbe 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -5,7 +5,6 @@
#include <stdio.h>
#include <termios.h>
-#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "chan_user.h"
@@ -30,7 +29,8 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts)
}
str++;
- if((data = um_kmalloc(sizeof(*data))) == NULL)
+ data = um_kmalloc(sizeof(*data));
+ if(data == NULL)
return(NULL);
*data = ((struct tty_chan) { .dev = str,
.raw = opts->raw });
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 0c3890b3ea127..8f212bfa74543 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -8,6 +8,13 @@
* old style ubd by setting UBD_SHIFT to 0
* 2002-09-27...2002-10-18 massive tinkering for 2.5
* partitions have changed in 2.5
+ * 2003-01-29 more tinkering for 2.5.59-1
+ * This should now address the sysfs problems and has
+ * the symlink for devfs to allow for booting with
+ * the common /dev/ubd/discX/... names rather than
+ * only /dev/ubdN/discN this version also has lots of
+ * clean ups preparing for ubd-many.
+ * James McMechan
*/
#define MAJOR_NR UBD_MAJOR
@@ -40,9 +47,12 @@
#include "mconsole_kern.h"
#include "init.h"
#include "irq_user.h"
+#include "irq_kern.h"
#include "ubd_user.h"
#include "2_5compat.h"
#include "os.h"
+#include "mem.h"
+#include "mem_kern.h"
static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED;
@@ -56,6 +66,10 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
#define MAX_DEV (8)
+/* Changed in early boot */
+static int ubd_do_mmap = 0;
+#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
+
static struct block_device_operations ubd_blops = {
.owner = THIS_MODULE,
.open = ubd_open,
@@ -67,7 +81,7 @@ static struct block_device_operations ubd_blops = {
static request_queue_t *ubd_queue;
/* Protected by ubd_lock */
-static int fake_major = 0;
+static int fake_major = MAJOR_NR;
static struct gendisk *ubd_gendisk[MAX_DEV];
static struct gendisk *fake_gendisk[MAX_DEV];
@@ -96,13 +110,19 @@ struct cow {
struct ubd {
char *file;
- int is_dir;
int count;
int fd;
__u64 size;
struct openflags boot_openflags;
struct openflags openflags;
+ int no_cow;
struct cow cow;
+
+ int map_writes;
+ int map_reads;
+ int nomap_writes;
+ int nomap_reads;
+ int write_maps;
};
#define DEFAULT_COW { \
@@ -115,21 +135,28 @@ struct ubd {
#define DEFAULT_UBD { \
.file = NULL, \
- .is_dir = 0, \
.count = 0, \
.fd = -1, \
.size = -1, \
.boot_openflags = OPEN_FLAGS, \
.openflags = OPEN_FLAGS, \
+ .no_cow = 0, \
.cow = DEFAULT_COW, \
+ .map_writes = 0, \
+ .map_reads = 0, \
+ .nomap_writes = 0, \
+ .nomap_reads = 0, \
+ .write_maps = 0, \
}
struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
static int ubd0_init(void)
{
- if(ubd_dev[0].file == NULL)
- ubd_dev[0].file = "root_fs";
+ struct ubd *dev = &ubd_dev[0];
+
+ if(dev->file == NULL)
+ dev->file = "root_fs";
return(0);
}
@@ -196,19 +223,46 @@ __uml_help(fake_ide_setup,
" Create ide0 entries that map onto ubd devices.\n\n"
);
+static int parse_unit(char **ptr)
+{
+ char *str = *ptr, *end;
+ int n = -1;
+
+ if(isdigit(*str)) {
+ n = simple_strtoul(str, &end, 0);
+ if(end == str)
+ return(-1);
+ *ptr = end;
+ }
+ else if (('a' <= *str) && (*str <= 'h')) {
+ n = *str - 'a';
+ str++;
+ *ptr = str;
+ }
+ return(n);
+}
+
static int ubd_setup_common(char *str, int *index_out)
{
+ struct ubd *dev;
struct openflags flags = global_openflags;
char *backing_file;
int n, err;
if(index_out) *index_out = -1;
- n = *str++;
+ n = *str;
if(n == '='){
- static int fake_major_allowed = 1;
char *end;
int major;
+ str++;
+ if(!strcmp(str, "mmap")){
+ CHOOSE_MODE(printk("mmap not supported by the ubd "
+ "driver in tt mode\n"),
+ ubd_do_mmap = 1);
+ return(0);
+ }
+
if(!strcmp(str, "sync")){
global_openflags.s = 1;
return(0);
@@ -220,20 +274,14 @@ static int ubd_setup_common(char *str, int *index_out)
return(1);
}
- if(!fake_major_allowed){
- printk(KERN_ERR "Can't assign a fake major twice\n");
- return(1);
- }
-
err = 1;
spin_lock(&ubd_lock);
- if(!fake_major_allowed){
+ if(fake_major != MAJOR_NR){
printk(KERN_ERR "Can't assign a fake major twice\n");
goto out1;
}
fake_major = major;
- fake_major_allowed = 0;
printk(KERN_INFO "Setting extra ubd major number to %d\n",
major);
@@ -243,25 +291,23 @@ static int ubd_setup_common(char *str, int *index_out)
return(err);
}
- if(n < '0'){
- printk(KERN_ERR "ubd_setup : index out of range\n"); }
-
- if((n >= '0') && (n <= '9')) n -= '0';
- else if((n >= 'a') && (n <= 'z')) n -= 'a';
- else {
- printk(KERN_ERR "ubd_setup : device syntax invalid\n");
+ n = parse_unit(&str);
+ if(n < 0){
+ printk(KERN_ERR "ubd_setup : couldn't parse unit number "
+ "'%s'\n", str);
return(1);
}
if(n >= MAX_DEV){
- printk(KERN_ERR "ubd_setup : index out of range "
- "(%d devices)\n", MAX_DEV);
+ printk(KERN_ERR "ubd_setup : index %d out of range "
+ "(%d devices)\n", n, MAX_DEV);
return(1);
}
err = 1;
spin_lock(&ubd_lock);
- if(ubd_dev[n].file != NULL){
+ dev = &ubd_dev[n];
+ if(dev->file != NULL){
printk(KERN_ERR "ubd_setup : device already configured\n");
goto out2;
}
@@ -276,6 +322,11 @@ static int ubd_setup_common(char *str, int *index_out)
flags.s = 1;
str++;
}
+ if (*str == 'd'){
+ dev->no_cow = 1;
+ str++;
+ }
+
if(*str++ != '='){
printk(KERN_ERR "ubd_setup : Expected '='\n");
goto out2;
@@ -284,14 +335,17 @@ static int ubd_setup_common(char *str, int *index_out)
err = 0;
backing_file = strchr(str, ',');
if(backing_file){
- *backing_file = '\0';
- backing_file++;
- }
- ubd_dev[n].file = str;
- if(ubd_is_dir(ubd_dev[n].file))
- ubd_dev[n].is_dir = 1;
- ubd_dev[n].cow.file = backing_file;
- ubd_dev[n].boot_openflags = flags;
+ if(dev->no_cow)
+ printk(KERN_ERR "Can't specify both 'd' and a "
+ "cow file\n");
+ else {
+ *backing_file = '\0';
+ backing_file++;
+ }
+ }
+ dev->file = str;
+ dev->cow.file = backing_file;
+ dev->boot_openflags = flags;
out2:
spin_unlock(&ubd_lock);
return(err);
@@ -321,8 +375,7 @@ __uml_help(ubd_setup,
static int fakehd_set = 0;
static int fakehd(char *str)
{
- printk(KERN_INFO
- "fakehd : Changing ubd name to \"hd\".\n");
+ printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
fakehd_set = 1;
return 1;
}
@@ -368,32 +421,42 @@ static void ubd_handler(void)
{
struct io_thread_req req;
struct request *rq = elv_next_request(ubd_queue);
- int n;
+ int n, err;
do_ubd = NULL;
intr_count++;
n = read_ubd_fs(thread_fd, &req, sizeof(req));
if(n != sizeof(req)){
printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
- "errno = %d\n", os_getpid(), -n);
+ "err = %d\n", os_getpid(), -n);
spin_lock(&ubd_io_lock);
end_request(rq, 0);
spin_unlock(&ubd_io_lock);
return;
}
- if((req.offset != ((__u64) (rq->sector)) << 9) ||
- (req.length != (rq->current_nr_sectors) << 9))
+ if((req.op != UBD_MMAP) &&
+ ((req.offset != ((__u64) (rq->sector)) << 9) ||
+ (req.length != (rq->current_nr_sectors) << 9)))
panic("I/O op mismatch");
+ if(req.map_fd != -1){
+ err = physmem_subst_mapping(req.buffer, req.map_fd,
+ req.map_offset, 1);
+ if(err)
+ printk("ubd_handler - physmem_subst_mapping failed, "
+ "err = %d\n", -err);
+ }
+
ubd_finish(rq, req.error);
reactivate_fd(thread_fd, UBD_IRQ);
do_ubd_request(ubd_queue);
}
-static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
+static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
{
ubd_handler();
+ return(IRQ_HANDLED);
}
/* Only changed by ubd_init, which is an initcall. */
@@ -417,10 +480,14 @@ static int ubd_file_size(struct ubd *dev, __u64 *size_out)
static void ubd_close(struct ubd *dev)
{
+ if(ubd_do_mmap)
+ physmem_forget_descriptor(dev->fd);
os_close_file(dev->fd);
if(dev->cow.file == NULL)
return;
+ if(ubd_do_mmap)
+ physmem_forget_descriptor(dev->cow.fd);
os_close_file(dev->cow.fd);
vfree(dev->cow.bitmap);
dev->cow.bitmap = NULL;
@@ -429,18 +496,20 @@ static void ubd_close(struct ubd *dev)
static int ubd_open_dev(struct ubd *dev)
{
struct openflags flags;
- int err, n, create_cow, *create_ptr;
+ char **back_ptr;
+ int err, create_cow, *create_ptr;
+ dev->openflags = dev->boot_openflags;
create_cow = 0;
create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
- dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file,
+ back_ptr = dev->no_cow ? NULL : &dev->cow.file;
+ dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
&dev->cow.bitmap_offset, &dev->cow.bitmap_len,
&dev->cow.data_offset, create_ptr);
if((dev->fd == -ENOENT) && create_cow){
- n = dev - ubd_dev;
dev->fd = create_cow_file(dev->file, dev->cow.file,
- dev->openflags, 1 << 9,
+ dev->openflags, 1 << 9, PAGE_SIZE,
&dev->cow.bitmap_offset,
&dev->cow.bitmap_len,
&dev->cow.data_offset);
@@ -455,13 +524,17 @@ static int ubd_open_dev(struct ubd *dev)
if(dev->cow.file != NULL){
err = -ENOMEM;
dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
- if(dev->cow.bitmap == NULL) goto error;
+ if(dev->cow.bitmap == NULL){
+ printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
+ goto error;
+ }
flush_tlb_kernel_vm();
err = read_cow_bitmap(dev->fd, dev->cow.bitmap,
dev->cow.bitmap_offset,
dev->cow.bitmap_len);
- if(err) goto error;
+ if(err < 0)
+ goto error;
flags = dev->openflags;
flags.w = 0;
@@ -481,17 +554,31 @@ static int ubd_new_disk(int major, u64 size, int unit,
{
struct gendisk *disk;
+ char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
+ int err;
disk = alloc_disk(1 << UBD_SHIFT);
- if (!disk)
- return -ENOMEM;
+ if(disk == NULL)
+ return(-ENOMEM);
disk->major = major;
disk->first_minor = unit << UBD_SHIFT;
disk->fops = &ubd_blops;
set_capacity(disk, size / 512);
- sprintf(disk->disk_name, "ubd");
- sprintf(disk->devfs_name, "ubd/disc%d", unit);
+ if(major == MAJOR_NR){
+ sprintf(disk->disk_name, "ubd%c", 'a' + unit);
+ sprintf(disk->devfs_name, "ubd/disc%d", unit);
+ sprintf(from, "ubd/%d", unit);
+ sprintf(to, "disc%d/disc", unit);
+ err = devfs_mk_symlink(from, to);
+ if(err)
+ printk("ubd_new_disk failed to make link from %s to "
+ "%s, error = %d\n", from, to, err);
+ }
+ else {
+ sprintf(disk->disk_name, "ubd_fake%d", unit);
+ sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
+ }
disk->private_data = &ubd_dev[unit];
disk->queue = ubd_queue;
@@ -506,24 +593,21 @@ static int ubd_add(int n)
struct ubd *dev = &ubd_dev[n];
int err;
- if(dev->is_dir)
- return(-EISDIR);
-
- if (!dev->file)
+ if(dev->file == NULL)
return(-ENODEV);
if (ubd_open_dev(dev))
return(-ENODEV);
err = ubd_file_size(dev, &dev->size);
- if(err)
+ if(err < 0)
return(err);
err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
if(err)
return(err);
- if(fake_major)
+ if(fake_major != MAJOR_NR)
ubd_new_disk(fake_major, dev->size, n,
&fake_gendisk[n]);
@@ -561,42 +645,42 @@ static int ubd_config(char *str)
return(err);
}
-static int ubd_get_config(char *dev, char *str, int size, char **error_out)
+static int ubd_get_config(char *name, char *str, int size, char **error_out)
{
- struct ubd *ubd;
+ struct ubd *dev;
char *end;
- int major, n = 0;
+ int n, len = 0;
- major = simple_strtoul(dev, &end, 0);
- if((*end != '\0') || (end == dev)){
- *error_out = "ubd_get_config : didn't parse major number";
+ n = simple_strtoul(name, &end, 0);
+ if((*end != '\0') || (end == name)){
+ *error_out = "ubd_get_config : didn't parse device number";
return(-1);
}
- if((major >= MAX_DEV) || (major < 0)){
- *error_out = "ubd_get_config : major number out of range";
+ if((n >= MAX_DEV) || (n < 0)){
+ *error_out = "ubd_get_config : device number out of range";
return(-1);
}
- ubd = &ubd_dev[major];
+ dev = &ubd_dev[n];
spin_lock(&ubd_lock);
- if(ubd->file == NULL){
- CONFIG_CHUNK(str, size, n, "", 1);
+ if(dev->file == NULL){
+ CONFIG_CHUNK(str, size, len, "", 1);
goto out;
}
- CONFIG_CHUNK(str, size, n, ubd->file, 0);
+ CONFIG_CHUNK(str, size, len, dev->file, 0);
- if(ubd->cow.file != NULL){
- CONFIG_CHUNK(str, size, n, ",", 0);
- CONFIG_CHUNK(str, size, n, ubd->cow.file, 1);
+ if(dev->cow.file != NULL){
+ CONFIG_CHUNK(str, size, len, ",", 0);
+ CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
}
- else CONFIG_CHUNK(str, size, n, "", 1);
+ else CONFIG_CHUNK(str, size, len, "", 1);
out:
spin_unlock(&ubd_lock);
- return(n);
+ return(len);
}
static int ubd_remove(char *str)
@@ -604,11 +688,9 @@ static int ubd_remove(char *str)
struct ubd *dev;
int n, err = -ENODEV;
- if(!isdigit(*str))
- return(err); /* it should be a number 0-7/a-h */
+ n = parse_unit(&str);
- n = *str - '0';
- if(n >= MAX_DEV)
+ if((n < 0) || (n >= MAX_DEV))
return(err);
dev = &ubd_dev[n];
@@ -669,7 +751,7 @@ int ubd_init(void)
elevator_init(ubd_queue, &elevator_noop);
- if (fake_major != 0) {
+ if (fake_major != MAJOR_NR) {
char name[sizeof("ubd_nnn\0")];
snprintf(name, sizeof(name), "ubd_%d", fake_major);
@@ -696,6 +778,7 @@ int ubd_driver_init(void){
io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *),
&thread_fd);
if(io_pid < 0){
+ io_pid = -1;
printk(KERN_ERR
"ubd : Failed to start I/O thread (errno = %d) - "
"falling back to synchronous I/O\n", -io_pid);
@@ -703,8 +786,8 @@ int ubd_driver_init(void){
}
err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
SA_INTERRUPT, "ubd", ubd_dev);
- if(err != 0) printk(KERN_ERR
- "um_request_irq failed - errno = %d\n", -err);
+ if(err != 0)
+ printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
return(err);
}
@@ -714,15 +797,9 @@ static int ubd_open(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ubd *dev = disk->private_data;
- int err = -EISDIR;
-
- if(dev->is_dir == 1)
- goto out;
+ int err = 0;
- err = 0;
if(dev->count == 0){
- dev->openflags = dev->boot_openflags;
-
err = ubd_open_dev(dev);
if(err){
printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
@@ -749,62 +826,156 @@ static int ubd_release(struct inode * inode, struct file * file)
return(0);
}
-void cowify_req(struct io_thread_req *req, struct ubd *dev)
+static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
+ __u64 *cow_offset, unsigned long *bitmap,
+ __u64 bitmap_offset, unsigned long *bitmap_words,
+ __u64 bitmap_len)
{
- int i, update_bitmap, sector = req->offset >> 9;
+ __u64 sector = io_offset >> 9;
+ int i, update_bitmap = 0;
+
+ for(i = 0; i < length >> 9; i++){
+ if(cow_mask != NULL)
+ ubd_set_bit(i, (unsigned char *) cow_mask);
+ if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
+ continue;
+
+ update_bitmap = 1;
+ ubd_set_bit(sector + i, (unsigned char *) bitmap);
+ }
+
+ if(!update_bitmap)
+ return;
+
+ *cow_offset = sector / (sizeof(unsigned long) * 8);
+
+ /* This takes care of the case where we're exactly at the end of the
+ * device, and *cow_offset + 1 is off the end. So, just back it up
+ * by one word. Thanks to Lynn Kerby for the fix and James McMechan
+ * for the original diagnosis.
+ */
+ if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /
+ sizeof(unsigned long) - 1))
+ (*cow_offset)--;
+
+ bitmap_words[0] = bitmap[*cow_offset];
+ bitmap_words[1] = bitmap[*cow_offset + 1];
+
+ *cow_offset *= sizeof(unsigned long);
+ *cow_offset += bitmap_offset;
+}
+
+static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
+ __u64 bitmap_offset, __u64 bitmap_len)
+{
+ __u64 sector = req->offset >> 9;
+ int i;
if(req->length > (sizeof(req->sector_mask) * 8) << 9)
panic("Operation too long");
+
if(req->op == UBD_READ) {
for(i = 0; i < req->length >> 9; i++){
- if(ubd_test_bit(sector + i, (unsigned char *)
- dev->cow.bitmap)){
+ if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
ubd_set_bit(i, (unsigned char *)
&req->sector_mask);
- }
}
- }
- else {
- update_bitmap = 0;
- for(i = 0; i < req->length >> 9; i++){
- ubd_set_bit(i, (unsigned char *)
- &req->sector_mask);
- if(!ubd_test_bit(sector + i, (unsigned char *)
- dev->cow.bitmap))
- update_bitmap = 1;
- ubd_set_bit(sector + i, (unsigned char *)
- dev->cow.bitmap);
- }
- if(update_bitmap){
- req->cow_offset = sector / (sizeof(unsigned long) * 8);
- req->bitmap_words[0] =
- dev->cow.bitmap[req->cow_offset];
- req->bitmap_words[1] =
- dev->cow.bitmap[req->cow_offset + 1];
- req->cow_offset *= sizeof(unsigned long);
- req->cow_offset += dev->cow.bitmap_offset;
+ }
+ else cowify_bitmap(req->offset, req->length, &req->sector_mask,
+ &req->cow_offset, bitmap, bitmap_offset,
+ req->bitmap_words, bitmap_len);
+}
+
+static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
+{
+ __u64 sector;
+ unsigned char *bitmap;
+ int bit, i;
+
+ /* mmap must have been requested on the command line */
+ if(!ubd_do_mmap)
+ return(-1);
+
+ /* The buffer must be page aligned */
+ if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
+ return(-1);
+
+ /* The request must be a page long */
+ if((req->current_nr_sectors << 9) != PAGE_SIZE)
+ return(-1);
+
+ if(dev->cow.file == NULL)
+ return(dev->fd);
+
+ sector = offset >> 9;
+ bitmap = (unsigned char *) dev->cow.bitmap;
+ bit = ubd_test_bit(sector, bitmap);
+
+ for(i = 1; i < req->current_nr_sectors; i++){
+ if(ubd_test_bit(sector + i, bitmap) != bit)
+ return(-1);
+ }
+
+ if(bit || (rq_data_dir(req) == WRITE))
+ offset += dev->cow.data_offset;
+
+ /* The data on disk must be page aligned */
+ if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
+ return(-1);
+
+ return(bit ? dev->fd : dev->cow.fd);
+}
+
+static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset,
+ struct request *req,
+ struct io_thread_req *io_req)
+{
+ int err;
+
+ if(rq_data_dir(req) == WRITE){
+ /* Writes are almost no-ops since the new data is already in the
+ * host page cache
+ */
+ dev->map_writes++;
+ if(dev->cow.file != NULL)
+ cowify_bitmap(io_req->offset, io_req->length,
+ &io_req->sector_mask, &io_req->cow_offset,
+ dev->cow.bitmap, dev->cow.bitmap_offset,
+ io_req->bitmap_words,
+ dev->cow.bitmap_len);
+ }
+ else {
+ int w;
+
+ if((dev->cow.file != NULL) && (fd == dev->cow.fd))
+ w = 0;
+ else w = dev->openflags.w;
+
+ if((dev->cow.file != NULL) && (fd == dev->fd))
+ offset += dev->cow.data_offset;
+
+ err = physmem_subst_mapping(req->buffer, fd, offset, w);
+ if(err){
+ printk("physmem_subst_mapping failed, err = %d\n",
+ -err);
+ return(1);
}
+ dev->map_reads++;
}
+ io_req->op = UBD_MMAP;
+ io_req->buffer = req->buffer;
+ return(0);
}
static int prepare_request(struct request *req, struct io_thread_req *io_req)
{
struct gendisk *disk = req->rq_disk;
struct ubd *dev = disk->private_data;
- __u64 block;
- int nsect;
+ __u64 offset;
+ int len, fd;
if(req->rq_status == RQ_INACTIVE) return(1);
- if(dev->is_dir){
- strcpy(req->buffer, "HOSTFS:");
- strcat(req->buffer, dev->file);
- spin_lock(&ubd_io_lock);
- end_request(req, 1);
- spin_unlock(&ubd_io_lock);
- return(1);
- }
-
if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
printk("Write attempted on readonly ubd device %s\n",
disk->disk_name);
@@ -814,23 +985,49 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
return(1);
}
- block = req->sector;
- nsect = req->current_nr_sectors;
+ offset = ((__u64) req->sector) << 9;
+ len = req->current_nr_sectors << 9;
- io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE;
io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
io_req->fds[1] = dev->fd;
+ io_req->map_fd = -1;
+ io_req->cow_offset = -1;
+ io_req->offset = offset;
+ io_req->length = len;
+ io_req->error = 0;
+ io_req->sector_mask = 0;
+
+ fd = mmap_fd(req, dev, io_req->offset);
+ if(fd > 0){
+ /* If mmapping is otherwise OK, but the first access to the
+ * page is a write, then it's not mapped in yet. So we have
+ * to write the data to disk first, then we can map the disk
+ * page in and continue normally from there.
+ */
+ if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){
+ io_req->map_fd = dev->fd;
+ io_req->map_offset = io_req->offset +
+ dev->cow.data_offset;
+ dev->write_maps++;
+ }
+ else return(prepare_mmap_request(dev, fd, io_req->offset, req,
+ io_req));
+ }
+
+ if(rq_data_dir(req) == READ)
+ dev->nomap_reads++;
+ else dev->nomap_writes++;
+
+ io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
io_req->offsets[0] = 0;
io_req->offsets[1] = dev->cow.data_offset;
- io_req->offset = ((__u64) block) << 9;
- io_req->length = nsect << 9;
io_req->buffer = req->buffer;
io_req->sectorsize = 1 << 9;
- io_req->sector_mask = 0;
- io_req->cow_offset = -1;
- io_req->error = 0;
- if(dev->cow.file != NULL) cowify_req(io_req, dev);
+ if(dev->cow.file != NULL)
+ cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
+ dev->cow.bitmap_len);
+
return(0);
}
@@ -841,7 +1038,7 @@ static void do_ubd_request(request_queue_t *q)
int err, n;
if(thread_fd == -1){
- while(!list_empty(&q->queue_head)){
+ while(!elv_queue_empty(q)){
req = elv_next_request(q);
err = prepare_request(req, &io_req);
if(!err){
@@ -851,7 +1048,8 @@ static void do_ubd_request(request_queue_t *q)
}
}
else {
- if(do_ubd || list_empty(&q->queue_head)) return;
+ if(do_ubd || elv_queue_empty(q))
+ return;
req = elv_next_request(q);
err = prepare_request(req, &io_req);
if(!err){
@@ -885,7 +1083,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
g.heads = 128;
g.sectors = 32;
g.cylinders = dev->size / (128 * 32 * 512);
- g.start = 2;
+ g.start = get_start_sect(inode->i_bdev);
return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
case HDIO_SET_UNMASKINTR:
@@ -935,6 +1133,142 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
return(-EINVAL);
}
+static int ubd_check_remapped(int fd, unsigned long address, int is_write,
+ __u64 offset)
+{
+ __u64 bitmap_offset;
+ unsigned long new_bitmap[2];
+ int i, err, n;
+
+ /* If it's not a write access, we can't do anything about it */
+ if(!is_write)
+ return(0);
+
+ /* We have a write */
+ for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
+ struct ubd *dev = &ubd_dev[i];
+
+ if((dev->fd != fd) && (dev->cow.fd != fd))
+ continue;
+
+ /* It's a write to a ubd device */
+
+ if(!dev->openflags.w){
+ /* It's a write access on a read-only device - probably
+ * shouldn't happen. If the kernel is trying to change
+ * something with no intention of writing it back out,
+ * then this message will clue us in that this needs
+ * fixing
+ */
+ printk("Write access to mapped page from readonly ubd "
+ "device %d\n", i);
+ return(0);
+ }
+
+ /* It's a write to a writeable ubd device - it must be COWed
+ * because, otherwise, the page would have been mapped in
+ * writeable
+ */
+
+ if(!dev->cow.file)
+ panic("Write fault on writeable non-COW ubd device %d",
+ i);
+
+ /* It should also be an access to the backing file since the
+ * COW pages should be mapped in read-write
+ */
+
+ if(fd == dev->fd)
+ panic("Write fault on a backing page of ubd "
+ "device %d\n", i);
+
+ /* So, we do the write, copying the backing data to the COW
+ * file...
+ */
+
+ err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
+ if(err < 0)
+ panic("Couldn't seek to %lld in COW file of ubd "
+ "device %d, err = %d",
+ offset + dev->cow.data_offset, i, -err);
+
+ n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
+ if(n != PAGE_SIZE)
+ panic("Couldn't copy data to COW file of ubd "
+ "device %d, err = %d", i, -n);
+
+ /* ... updating the COW bitmap... */
+
+ cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset,
+ dev->cow.bitmap, dev->cow.bitmap_offset,
+ new_bitmap, dev->cow.bitmap_len);
+
+ err = os_seek_file(dev->fd, bitmap_offset);
+ if(err < 0)
+ panic("Couldn't seek to %lld in COW file of ubd "
+ "device %d, err = %d", bitmap_offset, i, -err);
+
+ n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
+ if(n != sizeof(new_bitmap))
+ panic("Couldn't update bitmap of ubd device %d, "
+ "err = %d", i, -n);
+
+ /* Maybe we can map the COW page in, and maybe we can't. If
+ * it is a pre-V3 COW file, we can't, since the alignment will
+ * be wrong. If it is a V3 or later COW file which has been
+ * moved to a system with a larger page size, then maybe we
+ * can't, depending on the exact location of the page.
+ */
+
+ offset += dev->cow.data_offset;
+
+ /* Remove the remapping, putting the original anonymous page
+ * back. If the COW file can be mapped in, that is done.
+ * Otherwise, the COW page is read in.
+ */
+
+ if(!physmem_remove_mapping((void *) address))
+ panic("Address 0x%lx not remapped by ubd device %d",
+ address, i);
+ if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
+ physmem_subst_mapping((void *) address, dev->fd,
+ offset, 1);
+ else {
+ err = os_seek_file(dev->fd, offset);
+ if(err < 0)
+ panic("Couldn't seek to %lld in COW file of "
+ "ubd device %d, err = %d", offset, i,
+ -err);
+
+ n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
+ if(n != PAGE_SIZE)
+ panic("Failed to read page from offset %llx of "
+ "COW file of ubd device %d, err = %d",
+ offset, i, -n);
+ }
+
+ return(1);
+ }
+
+ /* It's not a write on a ubd device */
+ return(0);
+}
+
+static struct remapper ubd_remapper = {
+ .list = LIST_HEAD_INIT(ubd_remapper.list),
+ .proc = ubd_check_remapped,
+};
+
+static int ubd_remapper_setup(void)
+{
+ if(ubd_do_mmap)
+ register_remapper(&ubd_remapper);
+
+ return(0);
+}
+
+__initcall(ubd_remapper_setup);
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index 93b6f3e90c22a..86727005970d3 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -11,11 +11,8 @@
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
-#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/fcntl.h>
#include <sys/socket.h>
-#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include "asm/types.h"
@@ -24,146 +21,30 @@
#include "user.h"
#include "ubd_user.h"
#include "os.h"
+#include "cow.h"
#include <endian.h>
#include <byteswap.h>
-#if __BYTE_ORDER == __BIG_ENDIAN
-# define ntohll(x) (x)
-# define htonll(x) (x)
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-# define ntohll(x) bswap_64(x)
-# define htonll(x) bswap_64(x)
-#else
-#error "__BYTE_ORDER not defined"
-#endif
-
-#define PATH_LEN_V1 256
-
-struct cow_header_v1 {
- int magic;
- int version;
- char backing_file[PATH_LEN_V1];
- time_t mtime;
- __u64 size;
- int sectorsize;
-};
-
-#define PATH_LEN_V2 MAXPATHLEN
-
-struct cow_header_v2 {
- unsigned long magic;
- unsigned long version;
- char backing_file[PATH_LEN_V2];
- time_t mtime;
- __u64 size;
- int sectorsize;
-};
-
-union cow_header {
- struct cow_header_v1 v1;
- struct cow_header_v2 v2;
-};
-
-#define COW_MAGIC 0x4f4f4f4d /* MOOO */
-#define COW_VERSION 2
-
-static void sizes(__u64 size, int sectorsize, int bitmap_offset,
- unsigned long *bitmap_len_out, int *data_offset_out)
-{
- *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
-
- *data_offset_out = bitmap_offset + *bitmap_len_out;
- *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
- *data_offset_out *= sectorsize;
-}
-
-static int read_cow_header(int fd, int *magic_out, char **backing_file_out,
- time_t *mtime_out, __u64 *size_out,
- int *sectorsize_out, int *bitmap_offset_out)
-{
- union cow_header *header;
- char *file;
- int err, n;
- unsigned long version, magic;
-
- header = um_kmalloc(sizeof(*header));
- if(header == NULL){
- printk("read_cow_header - Failed to allocate header\n");
- return(-ENOMEM);
- }
- err = -EINVAL;
- n = read(fd, header, sizeof(*header));
- if(n < offsetof(typeof(header->v1), backing_file)){
- printk("read_cow_header - short header\n");
- goto out;
- }
-
- magic = header->v1.magic;
- if(magic == COW_MAGIC) {
- version = header->v1.version;
- }
- else if(magic == ntohl(COW_MAGIC)){
- version = ntohl(header->v1.version);
- }
- else goto out;
-
- *magic_out = COW_MAGIC;
-
- if(version == 1){
- if(n < sizeof(header->v1)){
- printk("read_cow_header - failed to read V1 header\n");
- goto out;
- }
- *mtime_out = header->v1.mtime;
- *size_out = header->v1.size;
- *sectorsize_out = header->v1.sectorsize;
- *bitmap_offset_out = sizeof(header->v1);
- file = header->v1.backing_file;
- }
- else if(version == 2){
- if(n < sizeof(header->v2)){
- printk("read_cow_header - failed to read V2 header\n");
- goto out;
- }
- *mtime_out = ntohl(header->v2.mtime);
- *size_out = ntohll(header->v2.size);
- *sectorsize_out = ntohl(header->v2.sectorsize);
- *bitmap_offset_out = sizeof(header->v2);
- file = header->v2.backing_file;
- }
- else {
- printk("read_cow_header - invalid COW version\n");
- goto out;
- }
- err = -ENOMEM;
- *backing_file_out = uml_strdup(file);
- if(*backing_file_out == NULL){
- printk("read_cow_header - failed to allocate backing file\n");
- goto out;
- }
- err = 0;
- out:
- kfree(header);
- return(err);
-}
static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
{
- struct stat buf1, buf2;
+ struct uml_stat buf1, buf2;
+ int err;
if(from_cmdline == NULL) return(1);
if(!strcmp(from_cmdline, from_cow)) return(1);
- if(stat(from_cmdline, &buf1) < 0){
- printk("Couldn't stat '%s', errno = %d\n", from_cmdline,
- errno);
+ err = os_stat_file(from_cmdline, &buf1);
+ if(err < 0){
+ printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
return(1);
}
- if(stat(from_cow, &buf2) < 0){
- printk("Couldn't stat '%s', errno = %d\n", from_cow, errno);
+ err = os_stat_file(from_cow, &buf2);
+ if(err < 0){
+ printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
return(1);
}
- if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino))
+ if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
return(1);
printk("Backing file mismatch - \"%s\" requested,\n"
@@ -174,20 +55,21 @@ static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
{
- struct stat64 buf;
+ unsigned long modtime;
long long actual;
int err;
- if(stat64(file, &buf) < 0){
- printk("Failed to stat backing file \"%s\", errno = %d\n",
- file, errno);
- return(-errno);
+ err = os_file_modtime(file, &modtime);
+ if(err < 0){
+ printk("Failed to get modification time of backing file "
+ "\"%s\", err = %d\n", file, -err);
+ return(err);
}
err = os_file_size(file, &actual);
- if(err){
+ if(err < 0){
printk("Failed to get size of backing file \"%s\", "
- "errno = %d\n", file, -err);
+ "err = %d\n", file, -err);
return(err);
}
@@ -196,9 +78,9 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
"file\n", size, actual);
return(-EINVAL);
}
- if(buf.st_mtime != mtime){
+ if(modtime != mtime){
printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
- "file\n", mtime, buf.st_mtime);
+ "file\n", mtime, modtime);
return(-EINVAL);
}
return(0);
@@ -209,124 +91,16 @@ int read_cow_bitmap(int fd, void *buf, int offset, int len)
int err;
err = os_seek_file(fd, offset);
- if(err != 0) return(-errno);
- err = read(fd, buf, len);
- if(err < 0) return(-errno);
- return(0);
-}
+ if(err < 0)
+ return(err);
-static int absolutize(char *to, int size, char *from)
-{
- char save_cwd[256], *slash;
- int remaining;
+ err = os_read_file(fd, buf, len);
+ if(err < 0)
+ return(err);
- if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
- printk("absolutize : unable to get cwd - errno = %d\n", errno);
- return(-1);
- }
- slash = strrchr(from, '/');
- if(slash != NULL){
- *slash = '\0';
- if(chdir(from)){
- *slash = '/';
- printk("absolutize : Can't cd to '%s' - errno = %d\n",
- from, errno);
- return(-1);
- }
- *slash = '/';
- if(getcwd(to, size) == NULL){
- printk("absolutize : unable to get cwd of '%s' - "
- "errno = %d\n", from, errno);
- return(-1);
- }
- remaining = size - strlen(to);
- if(strlen(slash) + 1 > remaining){
- printk("absolutize : unable to fit '%s' into %d "
- "chars\n", from, size);
- return(-1);
- }
- strcat(to, slash);
- }
- else {
- if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
- printk("absolutize : unable to fit '%s' into %d "
- "chars\n", from, size);
- return(-1);
- }
- strcpy(to, save_cwd);
- strcat(to, "/");
- strcat(to, from);
- }
- chdir(save_cwd);
return(0);
}
-static int write_cow_header(char *cow_file, int fd, char *backing_file,
- int sectorsize, long long *size)
-{
- struct cow_header_v2 *header;
- struct stat64 buf;
- int err;
-
- err = os_seek_file(fd, 0);
- if(err != 0){
- printk("write_cow_header - lseek failed, errno = %d\n", errno);
- return(-errno);
- }
-
- err = -ENOMEM;
- header = um_kmalloc(sizeof(*header));
- if(header == NULL){
- printk("Failed to allocate COW V2 header\n");
- goto out;
- }
- header->magic = htonl(COW_MAGIC);
- header->version = htonl(COW_VERSION);
-
- err = -EINVAL;
- if(strlen(backing_file) > sizeof(header->backing_file) - 1){
- printk("Backing file name \"%s\" is too long - names are "
- "limited to %d characters\n", backing_file,
- sizeof(header->backing_file) - 1);
- goto out_free;
- }
-
- if(absolutize(header->backing_file, sizeof(header->backing_file),
- backing_file))
- goto out_free;
-
- err = stat64(header->backing_file, &buf);
- if(err < 0){
- printk("Stat of backing file '%s' failed, errno = %d\n",
- header->backing_file, errno);
- err = -errno;
- goto out_free;
- }
-
- err = os_file_size(header->backing_file, size);
- if(err){
- printk("Couldn't get size of backing file '%s', errno = %d\n",
- header->backing_file, -*size);
- goto out_free;
- }
-
- header->mtime = htonl(buf.st_mtime);
- header->size = htonll(*size);
- header->sectorsize = htonl(sectorsize);
-
- err = write(fd, header, sizeof(*header));
- if(err != sizeof(*header)){
- printk("Write of header to new COW file '%s' failed, "
- "errno = %d\n", cow_file, errno);
- goto out_free;
- }
- err = 0;
- out_free:
- kfree(header);
- out:
- return(err);
-}
-
int open_ubd_file(char *file, struct openflags *openflags,
char **backing_file_out, int *bitmap_offset_out,
unsigned long *bitmap_len_out, int *data_offset_out,
@@ -334,26 +108,36 @@ int open_ubd_file(char *file, struct openflags *openflags,
{
time_t mtime;
__u64 size;
+ __u32 version, align;
char *backing_file;
- int fd, err, sectorsize, magic, same, mode = 0644;
+ int fd, err, sectorsize, same, mode = 0644;
- if((fd = os_open_file(file, *openflags, mode)) < 0){
+ fd = os_open_file(file, *openflags, mode);
+ if(fd < 0){
if((fd == -ENOENT) && (create_cow_out != NULL))
*create_cow_out = 1;
if(!openflags->w ||
((errno != EROFS) && (errno != EACCES))) return(-errno);
openflags->w = 0;
- if((fd = os_open_file(file, *openflags, mode)) < 0)
+ fd = os_open_file(file, *openflags, mode);
+ if(fd < 0)
return(fd);
}
+
+ err = os_lock_file(fd, openflags->w);
+ if(err < 0){
+ printk("Failed to lock '%s', err = %d\n", file, -err);
+ goto out_close;
+ }
+
if(backing_file_out == NULL) return(fd);
- err = read_cow_header(fd, &magic, &backing_file, &mtime, &size,
- &sectorsize, bitmap_offset_out);
+ err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
+ &size, &sectorsize, &align, bitmap_offset_out);
if(err && (*backing_file_out != NULL)){
printk("Failed to read COW header from COW file \"%s\", "
- "errno = %d\n", file, err);
- goto error;
+ "errno = %d\n", file, -err);
+ goto out_close;
}
if(err) return(fd);
@@ -363,36 +147,33 @@ int open_ubd_file(char *file, struct openflags *openflags,
if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
printk("Switching backing file to '%s'\n", *backing_file_out);
- err = write_cow_header(file, fd, *backing_file_out,
- sectorsize, &size);
+ err = write_cow_header(file, fd, *backing_file_out,
+ sectorsize, align, &size);
if(err){
- printk("Switch failed, errno = %d\n", err);
+ printk("Switch failed, errno = %d\n", -err);
return(err);
}
}
else {
*backing_file_out = backing_file;
err = backing_file_mismatch(*backing_file_out, size, mtime);
- if(err) goto error;
+ if(err) goto out_close;
}
- sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out,
- data_offset_out);
+ cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
+ bitmap_len_out, data_offset_out);
return(fd);
- error:
- close(fd);
+ out_close:
+ os_close_file(fd);
return(err);
}
int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
- int sectorsize, int *bitmap_offset_out,
+ int sectorsize, int alignment, int *bitmap_offset_out,
unsigned long *bitmap_len_out, int *data_offset_out)
{
- __u64 blocks;
- long zero;
- int err, fd, i;
- long long size;
+ int err, fd;
flags.c = 1;
fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
@@ -403,57 +184,49 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
goto out;
}
- err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size);
- if(err) goto out_close;
-
- blocks = (size + sectorsize - 1) / sectorsize;
- blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8);
- zero = 0;
- for(i = 0; i < blocks; i++){
- err = write(fd, &zero, sizeof(zero));
- if(err != sizeof(zero)){
- printk("Write of bitmap to new COW file '%s' failed, "
- "errno = %d\n", cow_file, errno);
- goto out_close;
- }
- }
-
- sizes(size, sectorsize, sizeof(struct cow_header_v2),
- bitmap_len_out, data_offset_out);
- *bitmap_offset_out = sizeof(struct cow_header_v2);
-
- return(fd);
-
- out_close:
- close(fd);
+ err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
+ bitmap_offset_out, bitmap_len_out,
+ data_offset_out);
+ if(!err)
+ return(fd);
+ os_close_file(fd);
out:
return(err);
}
+/* XXX Just trivial wrappers around os_read_file and os_write_file */
int read_ubd_fs(int fd, void *buffer, int len)
{
- int n;
-
- n = read(fd, buffer, len);
- if(n < 0) return(-errno);
- else return(n);
+ return(os_read_file(fd, buffer, len));
}
int write_ubd_fs(int fd, char *buffer, int len)
{
- int n;
-
- n = write(fd, buffer, len);
- if(n < 0) return(-errno);
- else return(n);
+ return(os_write_file(fd, buffer, len));
}
-int ubd_is_dir(char *file)
+static int update_bitmap(struct io_thread_req *req)
{
- struct stat64 buf;
+ int n;
+
+ if(req->cow_offset == -1)
+ return(0);
+
+ n = os_seek_file(req->fds[1], req->cow_offset);
+ if(n < 0){
+ printk("do_io - bitmap lseek failed : err = %d\n", -n);
+ return(1);
+ }
+
+ n = os_write_file(req->fds[1], &req->bitmap_words,
+ sizeof(req->bitmap_words));
+ if(n != sizeof(req->bitmap_words)){
+ printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
+ req->fds[1]);
+ return(1);
+ }
- if(stat64(file, &buf) < 0) return(0);
- return(S_ISDIR(buf.st_mode));
+ return(0);
}
void do_io(struct io_thread_req *req)
@@ -461,8 +234,18 @@ void do_io(struct io_thread_req *req)
char *buf;
unsigned long len;
int n, nsectors, start, end, bit;
+ int err;
__u64 off;
+ if(req->op == UBD_MMAP){
+ /* Touch the page to force the host to do any necessary IO to
+ * get it into memory
+ */
+ n = *((volatile int *) req->buffer);
+ req->error = update_bitmap(req);
+ return;
+ }
+
nsectors = req->length / req->sectorsize;
start = 0;
do {
@@ -473,15 +256,14 @@ void do_io(struct io_thread_req *req)
&req->sector_mask) == bit))
end++;
- if(end != nsectors)
- printk("end != nsectors\n");
off = req->offset + req->offsets[bit] +
start * req->sectorsize;
len = (end - start) * req->sectorsize;
buf = &req->buffer[start * req->sectorsize];
- if(os_seek_file(req->fds[bit], off) != 0){
- printk("do_io - lseek failed : errno = %d\n", errno);
+ err = os_seek_file(req->fds[bit], off);
+ if(err < 0){
+ printk("do_io - lseek failed : err = %d\n", -err);
req->error = 1;
return;
}
@@ -490,11 +272,10 @@ void do_io(struct io_thread_req *req)
do {
buf = &buf[n];
len -= n;
- n = read(req->fds[bit], buf, len);
+ n = os_read_file(req->fds[bit], buf, len);
if (n < 0) {
- printk("do_io - read returned %d : "
- "errno = %d fd = %d\n", n,
- errno, req->fds[bit]);
+ printk("do_io - read failed, err = %d "
+ "fd = %d\n", -n, req->fds[bit]);
req->error = 1;
return;
}
@@ -502,11 +283,10 @@ void do_io(struct io_thread_req *req)
if (n < len) memset(&buf[n], 0, len - n);
}
else {
- n = write(req->fds[bit], buf, len);
+ n = os_write_file(req->fds[bit], buf, len);
if(n != len){
- printk("do_io - write returned %d : "
- "errno = %d fd = %d\n", n,
- errno, req->fds[bit]);
+ printk("do_io - write failed err = %d "
+ "fd = %d\n", -n, req->fds[bit]);
req->error = 1;
return;
}
@@ -515,24 +295,7 @@ void do_io(struct io_thread_req *req)
start = end;
} while(start < nsectors);
- if(req->cow_offset != -1){
- if(os_seek_file(req->fds[1], req->cow_offset) != 0){
- printk("do_io - bitmap lseek failed : errno = %d\n",
- errno);
- req->error = 1;
- return;
- }
- n = write(req->fds[1], &req->bitmap_words,
- sizeof(req->bitmap_words));
- if(n != sizeof(req->bitmap_words)){
- printk("do_io - bitmap update returned %d : "
- "errno = %d fd = %d\n", n, errno, req->fds[1]);
- req->error = 1;
- return;
- }
- }
- req->error = 0;
- return;
+ req->error = update_bitmap(req);
}
/* Changed in start_io_thread, which is serialized by being called only
@@ -550,19 +313,23 @@ int io_thread(void *arg)
signal(SIGWINCH, SIG_IGN);
while(1){
- n = read(kernel_fd, &req, sizeof(req));
- if(n < 0) printk("io_thread - read returned %d, errno = %d\n",
- n, errno);
- else if(n < sizeof(req)){
- printk("io_thread - short read : length = %d\n", n);
+ n = os_read_file(kernel_fd, &req, sizeof(req));
+ if(n != sizeof(req)){
+ if(n < 0)
+ printk("io_thread - read failed, fd = %d, "
+ "err = %d\n", kernel_fd, -n);
+ else {
+ printk("io_thread - short read, fd = %d, "
+ "length = %d\n", kernel_fd, n);
+ }
continue;
}
io_count++;
do_io(&req);
- n = write(kernel_fd, &req, sizeof(req));
+ n = os_write_file(kernel_fd, &req, sizeof(req));
if(n != sizeof(req))
- printk("io_thread - write failed, errno = %d\n",
- errno);
+ printk("io_thread - write failed, fd = %d, err = %d\n",
+ kernel_fd, -n);
}
}
@@ -571,10 +338,11 @@ int start_io_thread(unsigned long sp, int *fd_out)
int pid, fds[2], err;
err = os_pipe(fds, 1, 1);
- if(err){
- printk("start_io_thread - os_pipe failed, errno = %d\n", -err);
- return(-1);
+ if(err < 0){
+ printk("start_io_thread - os_pipe failed, err = %d\n", -err);
+ goto out;
}
+
kernel_fd = fds[0];
*fd_out = fds[1];
@@ -582,32 +350,19 @@ int start_io_thread(unsigned long sp, int *fd_out)
NULL);
if(pid < 0){
printk("start_io_thread - clone failed : errno = %d\n", errno);
- return(-errno);
- }
- return(pid);
-}
-
-#ifdef notdef
-int start_io_thread(unsigned long sp, int *fd_out)
-{
- int pid;
-
- if((kernel_fd = get_pty()) < 0) return(-1);
- raw(kernel_fd, 0);
- if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){
- printk("Couldn't open tty for IO\n");
- return(-1);
+ goto out_close;
}
- pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
- NULL);
- if(pid < 0){
- printk("start_io_thread - clone failed : errno = %d\n", errno);
- return(-errno);
- }
return(pid);
+
+ out_close:
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ kernel_fd = -1;
+ *fd_out = -1;
+ out:
+ return(err);
}
-#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 59c4ba89fe5db..dccdf3e90f9bd 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -8,7 +8,6 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <fcntl.h>
#include <termios.h>
#include <signal.h>
#include <sched.h>
@@ -36,7 +35,8 @@ void *xterm_init(char *str, int device, struct chan_opts *opts)
{
struct xterm_chan *data;
- if((data = malloc(sizeof(*data))) == NULL) return(NULL);
+ data = malloc(sizeof(*data));
+ if(data == NULL) return(NULL);
*data = ((struct xterm_chan) { .pid = -1,
.helper_pid = -1,
.device = device,
@@ -93,7 +93,7 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out)
"/usr/lib/uml/port-helper", "-uml-socket",
file, NULL };
- if(access(argv[4], X_OK))
+ if(os_access(argv[4], OS_ACC_X_OK) < 0)
argv[4] = "port-helper";
fd = mkstemp(file);
@@ -106,13 +106,13 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out)
printk("xterm_open : unlink failed, errno = %d\n", errno);
return(-errno);
}
- close(fd);
+ os_close_file(fd);
- fd = create_unix_socket(file, sizeof(file));
+ fd = os_create_unix_socket(file, sizeof(file), 1);
if(fd < 0){
printk("xterm_open : create_unix_socket failed, errno = %d\n",
-fd);
- return(-fd);
+ return(fd);
}
sprintf(title, data->title, data->device);
@@ -128,15 +128,16 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out)
if(data->direct_rcv)
new = os_rcv_fd(fd, &data->helper_pid);
else {
- if((err = os_set_fd_block(fd, 0)) != 0){
+ err = os_set_fd_block(fd, 0);
+ if(err < 0){
printk("xterm_open : failed to set descriptor "
- "non-blocking, errno = %d\n", err);
+ "non-blocking, err = %d\n", -err);
return(err);
}
new = xterm_fd(fd, &data->helper_pid);
}
if(new < 0){
- printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new);
+ printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
goto out;
}
@@ -160,7 +161,7 @@ void xterm_close(int fd, void *d)
if(data->helper_pid != -1)
os_kill_process(data->helper_pid, 0);
data->helper_pid = -1;
- close(fd);
+ os_close_file(fd);
}
void xterm_free(void *d)
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index 1b4683fe3c4fe..a94813fce4734 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -5,9 +5,12 @@
#include "linux/errno.h"
#include "linux/slab.h"
+#include "linux/signal.h"
+#include "linux/interrupt.h"
#include "asm/semaphore.h"
#include "asm/irq.h"
#include "irq_user.h"
+#include "irq_kern.h"
#include "kern_util.h"
#include "os.h"
#include "xterm.h"
@@ -19,17 +22,18 @@ struct xterm_wait {
int new_fd;
};
-static void xterm_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
{
struct xterm_wait *xterm = data;
int fd;
fd = os_rcv_fd(xterm->fd, &xterm->pid);
if(fd == -EAGAIN)
- return;
+ return(IRQ_NONE);
xterm->new_fd = fd;
up(&xterm->sem);
+ return(IRQ_HANDLED);
}
int xterm_fd(int socket, int *pid_out)
@@ -54,7 +58,8 @@ int xterm_fd(int socket, int *pid_out)
if(err){
printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
"err = %d\n", err);
- return(err);
+ ret = err;
+ goto out;
}
down(&data->sem);
@@ -62,6 +67,7 @@ int xterm_fd(int socket, int *pid_out)
ret = data->new_fd;
*pid_out = data->pid;
+ out:
kfree(data);
return(ret);
diff --git a/arch/um/dyn.lds.S b/arch/um/dyn.lds.S
index 361d9305a5fa8..78f96d09f6225 100644
--- a/arch/um/dyn.lds.S
+++ b/arch/um/dyn.lds.S
@@ -1,3 +1,5 @@
+#include <asm-generic/vmlinux.lds.h>
+
OUTPUT_FORMAT(ELF_FORMAT)
OUTPUT_ARCH(ELF_ARCH)
ENTRY(_start)
@@ -10,12 +12,15 @@ SECTIONS
{
. = START + SIZEOF_HEADERS;
.interp : { *(.interp) }
- . = ALIGN(4096);
__binary_start = .;
. = ALIGN(4096); /* Init code and data */
_stext = .;
__init_begin = .;
- .text.init : { *(.text.init) }
+ .init.text : {
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
. = ALIGN(4096);
@@ -55,7 +60,9 @@ SECTIONS
} =0x90909090
.plt : { *(.plt) }
.text : {
- *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.text)
+ SCHED_TEXT
+ *(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0x90909090
@@ -67,7 +74,7 @@ SECTIONS
#include "asm/common.lds.S"
- .data.init : { *(.data.init) }
+ init.data : { *(.init.data) }
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
diff --git a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
index 6d36d9c30b911..abdb015a4d710 100644
--- a/arch/um/include/2_5compat.h
+++ b/arch/um/include/2_5compat.h
@@ -6,20 +6,6 @@
#ifndef __2_5_COMPAT_H__
#define __2_5_COMPAT_H__
-#include "linux/version.h"
-
-#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
- name : dev_name, \
- write : write_proc, \
- read : NULL, \
- device : device_proc, \
- setup : setup_proc, \
- flags : f, \
- index : -1, \
- cflag : 0, \
- next : NULL \
-}
-
#define INIT_HARDSECT(arr, maj, sizes)
#define SET_PRI(task) do ; while(0)
diff --git a/arch/um/include/hostaudio.h b/arch/um/include/hostaudio.h
deleted file mode 100644
index 797b3f24e776e..0000000000000
--- a/arch/um/include/hostaudio.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2002 Steve Schmidtke
- * Licensed under the GPL
- */
-
-#ifndef HOSTAUDIO_H
-#define HOSTAUDIO_H
-
-#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
-#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
-
-struct hostaudio_state {
- int fd;
-};
-
-struct hostmixer_state {
- int fd;
-};
-
-/* UML user-side protoypes */
-extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer,
- size_t count, loff_t *ppos);
-extern ssize_t hostaudio_write_user(struct hostaudio_state *state,
- const char *buffer, size_t count,
- loff_t *ppos);
-extern int hostaudio_ioctl_user(struct hostaudio_state *state,
- unsigned int cmd, unsigned long arg);
-extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w,
- char *dsp);
-extern int hostaudio_release_user(struct hostaudio_state *state);
-extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state,
- unsigned int cmd, unsigned long arg);
-extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r,
- int w, char *mixer);
-extern int hostmixer_release_mixdev_user(struct hostmixer_state *state);
-
-#endif /* HOSTAUDIO_H */
-
-/*
- * 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/include/irq_kern.h b/arch/um/include/irq_kern.h
new file mode 100644
index 0000000000000..3af52a634c4c2
--- /dev/null
+++ b/arch/um/include/irq_kern.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __IRQ_KERN_H__
+#define __IRQ_KERN_H__
+
+#include "linux/interrupt.h"
+
+extern int um_request_irq(unsigned int irq, int fd, int type,
+ irqreturn_t (*handler)(int, void *,
+ struct pt_regs *),
+ unsigned long irqflags, const char * devname,
+ void *dev_id);
+
+#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/include/kern_util.h b/arch/um/include/kern_util.h
index 09e76a308e7fa..eace6b2084f89 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -60,12 +60,11 @@ extern void finish_fork(void);
extern void paging_init(void);
extern void init_flush_vm(void);
extern void *syscall_sp(void *t);
-extern void syscall_trace(void);
+extern void syscall_trace(union uml_pt_regs *regs, int entryexit);
extern int hz(void);
-extern void idle_timer(void);
+extern void uml_idle_timer(void);
extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
extern int external_pid(void *t);
-extern int pid_to_processor_id(int pid);
extern void boot_timer_handler(int sig);
extern void interrupt_end(void);
extern void initial_thread_cb(void (*proc)(void *), void *arg);
@@ -89,9 +88,7 @@ extern int remove_gdb(void);
extern char *uml_strdup(char *string);
extern void unprotect_kernel_mem(void);
extern void protect_kernel_mem(void);
-extern void set_kmem_end(unsigned long);
extern void uml_cleanup(void);
-extern int pid_to_processor_id(int pid);
extern void set_current(void *t);
extern void lock_signalled_task(void *t);
extern void IPI_handler(int cpu);
@@ -100,7 +97,9 @@ extern void *get_init_task(void);
extern int clear_user_proc(void *buf, int size);
extern int copy_to_user_proc(void *to, void *from, int size);
extern int copy_from_user_proc(void *to, void *from, int size);
+extern int strlen_user_proc(char *str);
extern void bus_handler(int sig, union uml_pt_regs *regs);
+extern void winch(int sig, union uml_pt_regs *regs);
extern long execute_syscall(void *r);
extern int smp_sigio_handler(void);
extern void *get_current(void);
@@ -111,6 +110,8 @@ extern void arch_switch(void);
extern void free_irq(unsigned int, void *);
extern int um_in_interrupt(void);
extern int cpu(void);
+extern unsigned long long time_stamp(void);
+
#endif
/*
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index e9783dc1619ff..31911329f2654 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -9,12 +9,14 @@
#include "linux/list.h"
#include "linux/workqueue.h"
#include "linux/tty.h"
+#include "linux/interrupt.h"
#include "asm/semaphore.h"
#include "chan_user.h"
#include "mconsole_kern.h"
struct line_driver {
char *name;
+ char *device_name;
char *devfs_name;
short major;
short minor_start;
@@ -67,8 +69,6 @@ struct lines {
#define LINES_INIT(n) { num : n }
-extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
-extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
extern void line_close(struct line *lines, struct tty_struct *tty);
extern int line_open(struct line *lines, struct tty_struct *tty,
struct chan_opts *opts);
diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
index 7eea2fac0f2ee..9fbe3083fdd8c 100644
--- a/arch/um/include/mconsole.h
+++ b/arch/um/include/mconsole.h
@@ -41,11 +41,13 @@ struct mconsole_notify {
struct mc_request;
+enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC };
+
struct mconsole_command
{
char *command;
void (*handler)(struct mc_request *req);
- int as_interrupt;
+ enum mc_context context;
};
struct mc_request
@@ -77,6 +79,8 @@ extern void mconsole_sysrq(struct mc_request *req);
extern void mconsole_cad(struct mc_request *req);
extern void mconsole_stop(struct mc_request *req);
extern void mconsole_go(struct mc_request *req);
+extern void mconsole_log(struct mc_request *req);
+extern void mconsole_proc(struct mc_request *req);
extern int mconsole_get_request(int fd, struct mc_request *req);
extern int mconsole_notify(char *sock_name, int type, const void *data,
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index bad6b30b8f7df..10c46c38949aa 100644
--- a/arch/um/include/mem.h
+++ b/arch/um/include/mem.h
@@ -1,19 +1,18 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#ifndef __MEM_H__
#define __MEM_H__
-struct vm_reserved {
- struct list_head list;
- unsigned long start;
- unsigned long end;
-};
+#include "linux/types.h"
-extern void set_usable_vm(unsigned long start, unsigned long end);
-extern void set_kmem_end(unsigned long new);
+extern int phys_mapping(unsigned long phys, __u64 *offset_out);
+extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
+extern int is_remapped(void *virt);
+extern int physmem_remove_mapping(void *virt);
+extern void physmem_forget_descriptor(int fd);
#endif
diff --git a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h
new file mode 100644
index 0000000000000..cb7e196d366b5
--- /dev/null
+++ b/arch/um/include/mem_kern.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MEM_KERN_H__
+#define __MEM_KERN_H__
+
+#include "linux/list.h"
+#include "linux/types.h"
+
+struct remapper {
+ struct list_head list;
+ int (*proc)(int, unsigned long, int, __u64);
+};
+
+extern void register_remapper(struct remapper *info);
+
+#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/include/mem_user.h b/arch/um/include/mem_user.h
index d80ac354bf289..f530ac3f81ede 100644
--- a/arch/um/include/mem_user.h
+++ b/arch/um/include/mem_user.h
@@ -32,43 +32,38 @@
#ifndef _MEM_USER_H
#define _MEM_USER_H
-struct mem_region {
+struct iomem_region {
+ struct iomem_region *next;
char *driver;
- unsigned long start_pfn;
- unsigned long start;
- unsigned long len;
- void *mem_map;
int fd;
+ int size;
+ unsigned long phys;
+ unsigned long virt;
};
-extern struct mem_region *regions[];
-extern struct mem_region physmem_region;
+extern struct iomem_region *iomem_regions;
+extern int iomem_size;
#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
extern unsigned long host_task_size;
extern unsigned long task_size;
+extern void check_devanon(void);
extern int init_mem_user(void);
extern int create_mem_file(unsigned long len);
-extern void setup_range(int fd, char *driver, unsigned long start,
- unsigned long pfn, unsigned long total, int need_vm,
- struct mem_region *region, void *reserved);
extern void setup_memory(void *entry);
extern unsigned long find_iomem(char *driver, unsigned long *len_out);
-extern int init_maps(struct mem_region *region);
-extern int nregions(void);
-extern int reserve_vm(unsigned long start, unsigned long end, void *e);
+extern int init_maps(unsigned long physmem, unsigned long iomem,
+ unsigned long highmem);
extern unsigned long get_vm(unsigned long len);
extern void setup_physmem(unsigned long start, unsigned long usable,
- unsigned long len);
-extern int setup_region(struct mem_region *region, void *entry);
+ unsigned long len, unsigned long highmem);
extern void add_iomem(char *name, int fd, unsigned long size);
-extern struct mem_region *phys_region(unsigned long phys);
extern unsigned long phys_offset(unsigned long phys);
extern void unmap_physmem(void);
-extern int map_memory(unsigned long virt, unsigned long phys,
- unsigned long len, int r, int w, int x);
+extern void map_memory(unsigned long virt, unsigned long phys,
+ unsigned long len, int r, int w, int x);
extern int protect_memory(unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed);
extern unsigned long get_kmem_end(void);
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index b9b1f0c1d9a97..d676d3dd1395a 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -17,6 +17,32 @@
#define OS_TYPE_FIFO 6
#define OS_TYPE_SOCK 7
+/* os_access() flags */
+#define OS_ACC_F_OK 0 /* Test for existence. */
+#define OS_ACC_X_OK 1 /* Test for execute permission. */
+#define OS_ACC_W_OK 2 /* Test for write permission. */
+#define OS_ACC_R_OK 4 /* Test for read permission. */
+#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
+
+/*
+ * types taken from stat_file() in hostfs_user.c
+ * (if they are wrong here, they are wrong there...).
+ */
+struct uml_stat {
+ int ust_dev; /* device */
+ unsigned long long ust_ino; /* inode */
+ int ust_mode; /* protection */
+ int ust_nlink; /* number of hard links */
+ int ust_uid; /* user ID of owner */
+ int ust_gid; /* group ID of owner */
+ unsigned long long ust_size; /* total size, in bytes */
+ int ust_blksize; /* blocksize for filesystem I/O */
+ unsigned long long ust_blocks; /* number of blocks allocated */
+ unsigned long ust_atime; /* time of last access */
+ unsigned long ust_mtime; /* time of last modification */
+ unsigned long ust_ctime; /* time of last change */
+};
+
struct openflags {
unsigned int r : 1;
unsigned int w : 1;
@@ -84,29 +110,47 @@ static inline struct openflags of_excl(struct openflags flags)
flags.e = 1;
return(flags);
}
-
+
static inline struct openflags of_cloexec(struct openflags flags)
{
flags.cl = 1;
return(flags);
}
+extern int os_stat_file(const char *file_name, struct uml_stat *buf);
+extern int os_stat_fd(const int fd, struct uml_stat *buf);
+extern int os_access(const char *file, int mode);
+extern void os_print_error(int error, const char* str);
+extern int os_get_exec_close(int fd, int *close_on_exec);
+extern int os_set_exec_close(int fd, int close_on_exec);
+extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
+extern int os_window_size(int fd, int *rows, int *cols);
+extern int os_new_tty_pgrp(int fd, int pid);
+extern int os_get_ifname(int fd, char *namebuf);
+extern int os_set_slip(int fd);
+extern int os_set_owner(int fd, int pid);
+extern int os_sigio_async(int master, int slave);
+extern int os_mode_fd(int fd, int mode);
+
extern int os_seek_file(int fd, __u64 offset);
extern int os_open_file(char *file, struct openflags flags, int mode);
extern int os_read_file(int fd, void *buf, int len);
-extern int os_write_file(int fd, void *buf, int count);
+extern int os_write_file(int fd, const void *buf, int count);
extern int os_file_size(char *file, long long *size_out);
+extern int os_file_modtime(char *file, unsigned long *modtime);
extern int os_pipe(int *fd, int stream, int close_on_exec);
extern int os_set_fd_async(int fd, int owner);
extern int os_set_fd_block(int fd, int blocking);
extern int os_accept_connection(int fd);
+extern int os_create_unix_socket(char *file, int len, int close_on_exec);
extern int os_shutdown_socket(int fd, int r, int w);
extern void os_close_file(int fd);
extern int os_rcv_fd(int fd, int *helper_pid_out);
-extern int create_unix_socket(char *file, int len);
+extern int create_unix_socket(char *file, int len, int close_on_exec);
extern int os_connect_socket(char *name);
extern int os_file_type(char *file);
extern int os_file_mode(char *file, struct openflags *mode_out);
+extern int os_lock_file(int fd, int excl);
extern unsigned long os_process_pc(int pid);
extern int os_process_parent(int pid);
@@ -115,11 +159,12 @@ extern void os_kill_process(int pid, int reap_child);
extern void os_usr1_process(int pid);
extern int os_getpid(void);
-extern int os_map_memory(void *virt, int fd, unsigned long off,
+extern int os_map_memory(void *virt, int fd, unsigned long long off,
unsigned long len, int r, int w, int x);
extern int os_protect_memory(void *addr, unsigned long len,
int r, int w, int x);
extern int os_unmap_memory(void *addr, int len);
+extern void os_flush_stdout(void);
#endif
diff --git a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h
index adaea4d5abeb0..b075e543d8649 100644
--- a/arch/um/include/signal_user.h
+++ b/arch/um/include/signal_user.h
@@ -11,6 +11,8 @@ extern int signal_stack_size;
extern int change_sig(int signal, int on);
extern void set_sigstack(void *stack, int size);
extern void set_handler(int sig, void (*handler)(int), int flags, ...);
+extern int set_signals(int enable);
+extern int get_signals(void);
#endif
diff --git a/arch/um/include/skas_ptrace.h b/arch/um/include/skas_ptrace.h
index 7cd983d88d518..cfb5fb4f5b91f 100644
--- a/arch/um/include/skas_ptrace.h
+++ b/arch/um/include/skas_ptrace.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h
index d1ca652a7a3fe..bac91c1b88da3 100644
--- a/arch/um/include/sysdep-i386/checksum.h
+++ b/arch/um/include/sysdep-i386/checksum.h
@@ -5,6 +5,7 @@
#ifndef __UM_SYSDEP_CHECKSUM_H
#define __UM_SYSDEP_CHECKSUM_H
+#include "linux/in6.h"
#include "linux/string.h"
/*
diff --git a/arch/um/include/sysdep-i386/frame_user.h b/arch/um/include/sysdep-i386/frame_user.h
index b4065b235ef57..13faf079ac2eb 100644
--- a/arch/um/include/sysdep-i386/frame_user.h
+++ b/arch/um/include/sysdep-i386/frame_user.h
@@ -56,26 +56,26 @@ static inline void setup_arch_frame(struct arch_frame_data_raw *in,
* it would have to be __builtin_frame_address(1).
*/
-static inline unsigned long frame_restorer(void)
-{
- unsigned long *fp;
-
- fp = __builtin_frame_address(0);
- return((unsigned long) (fp + 1));
-}
+#define frame_restorer() \
+({ \
+ unsigned long *fp; \
+\
+ fp = __builtin_frame_address(0); \
+ ((unsigned long) (fp + 1)); \
+})
/* Similarly, this returns the value of sp when the handler was first
* entered. This is used to calculate the proper sp when delivering
* signals.
*/
-static inline unsigned long frame_sp(void)
-{
- unsigned long *fp;
-
- fp = __builtin_frame_address(0);
- return((unsigned long) (fp + 1));
-}
+#define frame_sp() \
+({ \
+ unsigned long *fp; \
+\
+ fp = __builtin_frame_address(0); \
+ ((unsigned long) (fp + 1)); \
+})
#endif
diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
index 26c70cf8badb5..887fdb61ed77c 100644
--- a/arch/um/include/sysdep-i386/sigcontext.h
+++ b/arch/um/include/sysdep-i386/sigcontext.h
@@ -28,8 +28,8 @@
*/
#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
-/* These are General Protection and Page Fault */
-#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14))
+/* This is Page Fault */
+#define SEGV_IS_FIXABLE(trap) (trap == 14)
#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h
index 08d7c1323e423..47687dcf2b51b 100644
--- a/arch/um/include/sysdep-i386/syscalls.h
+++ b/arch/um/include/sysdep-i386/syscalls.h
@@ -11,39 +11,34 @@ typedef long syscall_handler_t(struct pt_regs);
#define EXECUTE_SYSCALL(syscall, regs) \
((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
-extern syscall_handler_t sys_modify_ldt;
-extern syscall_handler_t old_mmap_i386;
-extern syscall_handler_t old_select;
-extern syscall_handler_t sys_ni_syscall;
-
#define ARCH_SYSCALLS \
- [ __NR_mmap ] = old_mmap_i386, \
- [ __NR_select ] = old_select, \
- [ __NR_vm86old ] = sys_ni_syscall, \
- [ __NR_modify_ldt ] = sys_modify_ldt, \
- [ __NR_lchown32 ] = sys_lchown, \
- [ __NR_getuid32 ] = sys_getuid, \
- [ __NR_getgid32 ] = sys_getgid, \
- [ __NR_geteuid32 ] = sys_geteuid, \
- [ __NR_getegid32 ] = sys_getegid, \
- [ __NR_setreuid32 ] = sys_setreuid, \
- [ __NR_setregid32 ] = sys_setregid, \
- [ __NR_getgroups32 ] = sys_getgroups, \
- [ __NR_setgroups32 ] = sys_setgroups, \
- [ __NR_fchown32 ] = sys_fchown, \
- [ __NR_setresuid32 ] = sys_setresuid, \
- [ __NR_getresuid32 ] = sys_getresuid, \
- [ __NR_setresgid32 ] = sys_setresgid, \
- [ __NR_getresgid32 ] = sys_getresgid, \
- [ __NR_chown32 ] = sys_chown, \
- [ __NR_setuid32 ] = sys_setuid, \
- [ __NR_setgid32 ] = sys_setgid, \
- [ __NR_setfsuid32 ] = sys_setfsuid, \
- [ __NR_setfsgid32 ] = sys_setfsgid, \
- [ __NR_pivot_root ] = sys_pivot_root, \
- [ __NR_mincore ] = sys_mincore, \
- [ __NR_madvise ] = sys_madvise, \
- [ 222 ] = sys_ni_syscall,
+ [ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \
+ [ __NR_select ] = (syscall_handler_t *) old_select, \
+ [ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \
+ [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \
+ [ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \
+ [ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \
+ [ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \
+ [ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \
+ [ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \
+ [ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \
+ [ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \
+ [ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \
+ [ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \
+ [ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \
+ [ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \
+ [ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \
+ [ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \
+ [ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \
+ [ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \
+ [ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \
+ [ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \
+ [ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \
+ [ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \
+ [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \
+ [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \
+ [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \
+ [ 222 ] = (syscall_handler_t *) sys_ni_syscall,
/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
diff --git a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h
index b28beaf58bbdd..9bac59c4c9df4 100644
--- a/arch/um/include/ubd_user.h
+++ b/arch/um/include/ubd_user.h
@@ -9,7 +9,7 @@
#include "os.h"
-enum ubd_req { UBD_READ, UBD_WRITE };
+enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP };
struct io_thread_req {
enum ubd_req op;
@@ -20,8 +20,10 @@ struct io_thread_req {
char *buffer;
int sectorsize;
unsigned long sector_mask;
- unsigned long cow_offset;
+ unsigned long long cow_offset;
unsigned long bitmap_words[2];
+ int map_fd;
+ unsigned long long map_offset;
int error;
};
@@ -31,7 +33,7 @@ extern int open_ubd_file(char *file, struct openflags *openflags,
int *create_cow_out);
extern int create_cow_file(char *cow_file, char *backing_file,
struct openflags flags, int sectorsize,
- int *bitmap_offset_out,
+ int alignment, int *bitmap_offset_out,
unsigned long *bitmap_len_out,
int *data_offset_out);
extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
@@ -39,7 +41,6 @@ extern int read_ubd_fs(int fd, void *buffer, int len);
extern int write_ubd_fs(int fd, char *buffer, int len);
extern int start_io_thread(unsigned long sp, int *fds_out);
extern void do_io(struct io_thread_req *req);
-extern int ubd_is_dir(char *file);
static inline int ubd_test_bit(__u64 bit, unsigned char *data)
{
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index 41afa3a8f0865..c9b3574c6ea98 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -38,22 +38,73 @@ static inline int copy_to_user(void *to, const void *from, int n)
from, n));
}
+/*
+ * strncpy_from_user: - Copy a NUL terminated string from userspace.
+ * @dst: Destination address, in kernel space. This buffer must be at
+ * least @count bytes long.
+ * @src: Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from userspace to kernel space.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
+
static inline int strncpy_from_user(char *dst, const char *src, int count)
{
return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
dst, src, count));
}
+/*
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to: Destination address, in user space.
+ * @n: Number of bytes to zero.
+ *
+ * Zero a block of memory in user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
static inline int __clear_user(void *mem, int len)
{
return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
}
+/*
+ * clear_user: - Zero a block of memory in user space.
+ * @to: Destination address, in user space.
+ * @n: Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
static inline int clear_user(void *mem, int len)
{
return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
}
+/*
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ * @n: The maximum valid length
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than @n.
+ */
static inline int strnlen_user(const void *str, int len)
{
return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
diff --git a/arch/um/include/user.h b/arch/um/include/user.h
index 6f009be0f8db1..57ee9e2612284 100644
--- a/arch/um/include/user.h
+++ b/arch/um/include/user.h
@@ -14,6 +14,9 @@ extern void *um_kmalloc_atomic(int size);
extern void kfree(void *ptr);
extern int in_aton(char *str);
extern int open_gdb_chan(void);
+extern int strlcpy(char *, const char *, int);
+extern void *um_vmalloc(int size);
+extern void vfree(void *ptr);
#endif
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index e87b8fcb00293..89ccc90e7d890 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -14,8 +14,6 @@ extern int grantpt(int __fd);
extern int unlockpt(int __fd);
extern char *ptsname(int __fd);
-enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
-
struct cpu_task {
int pid;
void *task;
@@ -59,13 +57,11 @@ extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern void *add_signal_handler(int sig, void (*handler)(int));
extern int start_fork_tramp(void *arg, unsigned long temp_stack,
int clone_flags, int (*tramp)(void *));
-extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
extern int linux_main(int argc, char **argv);
extern void set_cmdline(char *cmd);
extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
extern int get_pty(void);
extern void *um_kmalloc(int size);
-extern int raw(int fd, int complain);
extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
@@ -86,11 +82,17 @@ extern void check_sigio(void);
extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
extern void write_sigio_workaround(void);
extern void arch_check_bugs(void);
+extern int cpu_feature(char *what, char *buf, int len);
extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
extern int arch_fixup(unsigned long address, void *sc_ptr);
extern void forward_pending_sigio(int target);
extern int can_do_skas(void);
-
+extern void arch_init_thread(void);
+
+extern int __raw(int fd, int complain, int now);
+#define raw(fd, complain) __raw((fd), (complain), 1)
+
+#define CATCH_EINTR(expr) while ( ((expr) < 0) && errno == EINTR)
#endif
/*
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index ccaa771204ea5..72d9210ebe9f7 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -3,15 +3,15 @@
# Licensed under the GPL
#
-extra-y := vmlinux.lds
+extra-y := vmlinux.lds uml.lds
obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \
- helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
- process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
- sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \
- syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \
- time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
- umid.o user_syms.o user_util.o
+ helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \
+ physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
+ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
+ syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \
+ time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \
+ um_arch.o umid.o user_util.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
obj-$(CONFIG_GPROF) += gprof_syms.o
@@ -24,43 +24,27 @@ obj-$(CONFIG_MODE_SKAS) += skas/
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \
- process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o
+ main.o process.o tempfile.o time.o tty_log.o umid.o user_util.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__
-DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__
-
-
-CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \
- -I/usr/include -I../include
-
CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
-$(USER_OBJS) : %.o: %.c
- $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
# This has to be separate because it needs be compiled with frame pointers
# regardless of how the rest of the kernel is built.
$(obj)/frame.o: $(src)/frame.c
$(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $<
-QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config
- $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@
+QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
$(obj)/config.o : $(obj)/config.c
-clean:
- rm -f config.c
- for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
-
-modules:
-
-fastdep:
-
-dep:
-
-archmrproper: clean
+quiet_cmd_quote = QUOTE $@
+cmd_quote = $(PERL) -e $(QUOTE) < $< > $@
+targets += config.c
+$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config FORCE
+ $(call if_changed,quote)
diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
index f6c96b9553837..c062cbfe386e2 100644
--- a/arch/um/kernel/config.c.in
+++ b/arch/um/kernel/config.c.in
@@ -7,9 +7,7 @@
#include <stdlib.h>
#include "init.h"
-static __initdata char *config = "
-CONFIG
-";
+static __initdata char *config = "CONFIG";
static int __init print_config(char *line, int *add)
{
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
index a6be6b542b4ae..a5f21283d2cd8 100644
--- a/arch/um/kernel/exec_kern.c
+++ b/arch/um/kernel/exec_kern.c
@@ -32,10 +32,15 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
}
+extern void log_exec(char **argv, void *tty);
+
static int execve1(char *file, char **argv, char **env)
{
int error;
+#ifdef CONFIG_TTY_LOG
+ log_exec(argv, current->tty);
+#endif
error = do_execve(file, argv, env, &current->thread.regs);
if (error == 0){
current->ptrace &= ~PT_DTRACE;
diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c
index d8993f293ae28..4b349f20795dd 100644
--- a/arch/um/kernel/frame.c
+++ b/arch/um/kernel/frame.c
@@ -21,6 +21,7 @@
#include "sysdep/sigcontext.h"
#include "frame_user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "ptrace_user.h"
#include "os.h"
@@ -40,7 +41,7 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
/* Wait for it to stop itself and continue it with a SIGUSR1 to force
* it into the signal handler.
*/
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0){
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
@@ -60,7 +61,7 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
* At this point, the handler has stuffed the addresses of
* sig, sc, and SA_RESTORER in raw.
*/
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0){
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
@@ -82,7 +83,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
errno);
exit(1);
}
- if(waitpid(pid, &status, 0) < 0){
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
+ if(n < 0){
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
}
@@ -279,7 +281,7 @@ void capture_signal_stack(void)
struct sc_frame_raw raw_sc;
struct si_frame_raw raw_si;
void *stack, *sigstack;
- unsigned long top, sig_top, base;
+ unsigned long top, base;
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -292,7 +294,6 @@ void capture_signal_stack(void)
}
top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
- sig_top = (unsigned long) sigstack + PAGE_SIZE;
/* Get the sigcontext, no sigrestorer layout */
raw_sc.restorer = 0;
diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c
index 9ff437466fee8..809002dade5a5 100644
--- a/arch/um/kernel/frame_kern.c
+++ b/arch/um/kernel/frame_kern.c
@@ -6,7 +6,6 @@
#include "asm/ptrace.h"
#include "asm/uaccess.h"
#include "asm/signal.h"
-#include "asm/uaccess.h"
#include "asm/ucontext.h"
#include "frame_kern.h"
#include "sigcontext.h"
@@ -29,12 +28,15 @@ static int copy_restorer(void (*restorer)(void), unsigned long start,
sizeof(restorer)));
}
+extern int userspace_pid[];
+
static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from,
struct arch_frame_data *arch)
{
return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
arch),
- copy_sc_to_user_skas(to, fp, &from->regs,
+ copy_sc_to_user_skas(userspace_pid[0], to, fp,
+ &from->regs,
current->thread.cr2,
current->thread.err)));
}
diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
index 5c4b27942da38..1f166e9a2b2bd 100644
--- a/arch/um/kernel/helper.c
+++ b/arch/um/kernel/helper.c
@@ -7,12 +7,12 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
-#include <fcntl.h>
#include <sched.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "os.h"
struct helper_data {
@@ -33,6 +33,7 @@ static int helper_child(void *arg)
{
struct helper_data *data = arg;
char **argv = data->argv;
+ int errval;
if(helper_pause){
signal(SIGHUP, helper_hup);
@@ -41,8 +42,9 @@ static int helper_child(void *arg)
if(data->pre_exec != NULL)
(*data->pre_exec)(data->pre_data);
execvp(argv[0], argv);
+ errval = errno;
printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
- write(data->fd, &errno, sizeof(errno));
+ os_write_file(data->fd, &errval, sizeof(errval));
os_kill_process(os_getpid(), 0);
return(0);
}
@@ -59,17 +61,20 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
if((stack_out != NULL) && (*stack_out != 0))
stack = *stack_out;
else stack = alloc_stack(0, um_in_interrupt());
- if(stack == 0) return(-ENOMEM);
+ if(stack == 0)
+ return(-ENOMEM);
err = os_pipe(fds, 1, 0);
- if(err){
- printk("run_helper : pipe failed, errno = %d\n", -err);
- return(err);
+ if(err < 0){
+ printk("run_helper : pipe failed, err = %d\n", -err);
+ goto out_free;
}
- if(fcntl(fds[1], F_SETFD, 1) != 0){
- printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n",
- errno);
- return(-errno);
+
+ err = os_set_exec_close(fds[1], 1);
+ if(err < 0){
+ printk("run_helper : setting FD_CLOEXEC failed, err = %d\n",
+ -err);
+ goto out_close;
}
sp = stack + page_size() - sizeof(void *);
@@ -80,23 +85,34 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
if(pid < 0){
printk("run_helper : clone failed, errno = %d\n", errno);
- return(-errno);
+ err = -errno;
+ goto out_close;
}
- close(fds[1]);
- n = read(fds[0], &err, sizeof(err));
+
+ os_close_file(fds[1]);
+ n = os_read_file(fds[0], &err, sizeof(err));
if(n < 0){
- printk("run_helper : read on pipe failed, errno = %d\n",
- errno);
- return(-errno);
+ printk("run_helper : read on pipe failed, err = %d\n", -n);
+ err = n;
+ goto out_kill;
}
else if(n != 0){
- waitpid(pid, NULL, 0);
- pid = -err;
+ CATCH_EINTR(n = waitpid(pid, NULL, 0));
+ pid = -errno;
}
if(stack_out == NULL) free_stack(stack, 0);
else *stack_out = stack;
return(pid);
+
+ out_kill:
+ os_kill_process(pid, 1);
+ out_close:
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ out_free:
+ free_stack(stack, 0);
+ return(err);
}
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
@@ -117,9 +133,11 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
}
if(stack_out == NULL){
pid = waitpid(pid, &status, 0);
- if(pid < 0)
+ if(pid < 0){
printk("run_helper_thread - wait failed, errno = %d\n",
- pid);
+ errno);
+ pid = -errno;
+ }
if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
printk("run_helper_thread - thread returned status "
"0x%x\n", status);
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index be82cafe908c4..cd7c85be0a1b7 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -8,7 +8,6 @@
#include "linux/module.h"
#include "linux/sched.h"
#include "linux/init_task.h"
-#include "linux/version.h"
#include "linux/mqueue.h"
#include "asm/uaccess.h"
#include "asm/pgtable.h"
@@ -19,7 +18,7 @@ static struct fs_struct init_fs = INIT_FS;
struct mm_struct init_mm = INIT_MM(init_mm);
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
EXPORT_SYMBOL(init_mm);
/*
@@ -44,26 +43,12 @@ union thread_union init_thread_union
__attribute__((__section__(".data.init_task"))) =
{ INIT_THREAD_INFO(init_task) };
-struct task_struct *alloc_task_struct(void)
-{
- return((struct task_struct *)
- __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER));
-}
-
void unprotect_stack(unsigned long stack)
{
protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
1, 1, 0, 1);
}
-void free_task_struct(struct task_struct *task)
-{
- /* free_pages decrements the page counter and only actually frees
- * the pages if they are now not accessed by anything.
- */
- free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER);
-}
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c
index 944c734ca9995..57d5b41dbab1d 100644
--- a/arch/um/kernel/initrd_user.c
+++ b/arch/um/kernel/initrd_user.c
@@ -6,7 +6,6 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
#include "user_util.h"
@@ -19,13 +18,15 @@ int load_initrd(char *filename, void *buf, int size)
{
int fd, n;
- if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){
- printk("Opening '%s' failed - errno = %d\n", filename, errno);
+ fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Opening '%s' failed - err = %d\n", filename, -fd);
return(-1);
}
- if((n = read(fd, buf, size)) != size){
- printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
- size, filename, n, errno);
+ n = os_read_file(fd, buf, size);
+ if(n != size){
+ printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+ filename, -n);
return(-1);
}
return(0);
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 0e968bb11a45c..ca43d4a79a1e7 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -18,6 +18,7 @@
#include "linux/proc_fs.h"
#include "linux/init.h"
#include "linux/seq_file.h"
+#include "linux/profile.h"
#include "asm/irq.h"
#include "asm/hw_irq.h"
#include "asm/hardirq.h"
@@ -29,6 +30,7 @@
#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
+#include "irq_kern.h"
static void register_irq_proc (unsigned int irq);
@@ -83,65 +85,55 @@ struct hw_interrupt_type no_irq_type = {
end_none
};
-/* Not changed */
-volatile unsigned long irq_err_count;
-
/*
* Generic, controller-independent functions:
*/
-int get_irq_list(char *buf)
+int show_interrupts(struct seq_file *p, void *v)
{
- int i, j;
- unsigned long flags;
+ int i = *(loff_t *) v, j;
struct irqaction * action;
- char *p = buf;
+ unsigned long flags;
- p += sprintf(p, " ");
- for (j=0; j<num_online_cpus(); j++)
- p += sprintf(p, "CPU%d ",j);
- *p++ = '\n';
+ if (i == 0) {
+ seq_printf(p, " ");
+ for (j=0; j<NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "CPU%d ",j);
+ seq_putc(p, '\n');
+ }
- for (i = 0 ; i < NR_IRQS ; i++) {
+ if (i < NR_IRQS) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
if (!action)
- goto end;
- p += sprintf(p, "%3d: ",i);
+ goto skip;
+ seq_printf(p, "%3d: ",i);
#ifndef CONFIG_SMP
- p += sprintf(p, "%10u ", kstat_irqs(i));
+ seq_printf(p, "%10u ", kstat_irqs(i));
#else
- for (j = 0; j < num_online_cpus(); j++)
- p += sprintf(p, "%10u ",
- kstat_cpu(cpu_logical_map(j)).irqs[i]);
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- p += sprintf(p, " %14s", irq_desc[i].handler->typename);
- p += sprintf(p, " %s", action->name);
+ seq_printf(p, " %14s", irq_desc[i].handler->typename);
+ seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
- p += sprintf(p, ", %s", action->name);
- *p++ = '\n';
- end:
+ seq_printf(p, ", %s", action->name);
+
+ seq_putc(p, '\n');
+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));
+ seq_putc(p, '\n');
}
- p += sprintf(p, "\n");
-#ifdef notdef
-#ifdef CONFIG_SMP
- p += sprintf(p, "LOC: ");
- for (j = 0; j < num_online_cpus(); j++)
- p += sprintf(p, "%10u ",
- apic_timer_irqs[cpu_logical_map(j)]);
- p += sprintf(p, "\n");
-#endif
-#endif
- p += sprintf(p, "ERR: %10lu\n", irq_err_count);
- return p - buf;
-}
-
-int show_interrupts(struct seq_file *p, void *v)
-{
- return(0);
+ return 0;
}
/*
@@ -282,13 +274,12 @@ unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
* 0 return value means that this irq is already being
* handled by some other CPU. (or is disabled)
*/
- int cpu = smp_processor_id();
irq_desc_t *desc = irq_desc + irq;
struct irqaction * action;
unsigned int status;
irq_enter();
- kstat_cpu(cpu).irqs[irq]++;
+ kstat_this_cpu.irqs[irq]++;
spin_lock(&desc->lock);
desc->handler->ack(irq);
/*
@@ -385,7 +376,7 @@ out:
*/
int request_irq(unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
+ irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char * devname,
void *dev_id)
@@ -433,15 +424,19 @@ int request_irq(unsigned int irq,
EXPORT_SYMBOL(request_irq);
int um_request_irq(unsigned int irq, int fd, int type,
- void (*handler)(int, void *, struct pt_regs *),
+ irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char * devname,
void *dev_id)
{
- int retval;
+ int err;
+
+ err = request_irq(irq, handler, irqflags, devname, dev_id);
+ if(err)
+ return(err);
- retval = request_irq(irq, handler, irqflags, devname, dev_id);
- if(retval) return(retval);
- return(activate_fd(irq, fd, type, dev_id));
+ if(fd != -1)
+ err = activate_fd(irq, fd, type, dev_id);
+ return(err);
}
/* this was setup_x86_irq but it seems pretty generic */
@@ -474,7 +469,8 @@ int setup_irq(unsigned int irq, struct irqaction * new)
*/
spin_lock_irqsave(&desc->lock,flags);
p = &desc->action;
- if ((old = *p) != NULL) {
+ old = *p;
+ if (old != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) {
spin_unlock_irqrestore(&desc->lock,flags);
@@ -586,12 +582,14 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
unsigned long count, void *data)
{
int irq = (long) data, full_count = count, err;
- cpumask_t new_value, tmp;
+ cpumask_t new_value;
if (!irq_desc[irq].handler->set_affinity)
return -EIO;
err = cpumask_parse(buffer, count, new_value);
+ if(err)
+ return(err);
#ifdef CONFIG_SMP
/*
@@ -599,9 +597,11 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
* way to make the system unusable accidentally :-) At least
* one online CPU still has to be targeted.
*/
- cpus_and(tmp, new_value, cpu_online_map);
- if (cpus_empty(tmp))
- return -EINVAL;
+ { cpumask_t tmp;
+ cpus_and(tmp, new_value, cpu_online_map);
+ if (cpus_empty(tmp))
+ return -EINVAL;
+ }
#endif
irq_affinity[irq] = new_value;
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
index 57fe9bb72655d..87ac2b038a91a 100644
--- a/arch/um/kernel/irq_user.c
+++ b/arch/um/kernel/irq_user.c
@@ -6,7 +6,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/poll.h>
@@ -49,7 +48,8 @@ void sigio_handler(int sig, union uml_pt_regs *regs)
if(smp_sigio_handler()) return;
while(1){
- if((n = poll(pollfds, pollfds_num, 0)) < 0){
+ n = poll(pollfds, pollfds_num, 0);
+ if(n < 0){
if(errno == EINTR) continue;
printk("sigio_handler : poll returned %d, "
"errno = %d\n", n, errno);
@@ -366,34 +366,31 @@ void deactivate_fd(int fd, int irqnum)
void forward_ipi(int fd, int pid)
{
- if(fcntl(fd, F_SETOWN, pid) < 0){
- int save_errno = errno;
- if(fcntl(fd, F_GETOWN, 0) != pid){
- printk("forward_ipi: F_SETOWN failed, fd = %d, "
- "me = %d, target = %d, errno = %d\n", fd,
- os_getpid(), pid, save_errno);
- }
- }
+ int err;
+
+ err = os_set_owner(fd, pid);
+ if(err < 0)
+ printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
+ "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
}
void forward_interrupts(int pid)
{
struct irq_fd *irq;
unsigned long flags;
+ int err;
flags = irq_lock();
for(irq=active_fds;irq != NULL;irq = irq->next){
- if(fcntl(irq->fd, F_SETOWN, pid) < 0){
- int save_errno = errno;
- if(fcntl(irq->fd, F_GETOWN, 0) != pid){
- /* XXX Just remove the irq rather than
- * print out an infinite stream of these
- */
- printk("Failed to forward %d to pid %d, "
- "errno = %d\n", irq->fd, pid,
- save_errno);
- }
+ err = os_set_owner(irq->fd, pid);
+ if(err < 0){
+ /* XXX Just remove the irq rather than
+ * print out an infinite stream of these
+ */
+ printk("Failed to forward %d to pid %d, err = %d\n",
+ irq->fd, pid, -err);
}
+
irq->pid = pid;
}
irq_unlock(flags);
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 1f82ad73aae5c..cb12aa824cff4 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -8,7 +8,7 @@
#include "linux/string.h"
#include "linux/smp_lock.h"
#include "linux/spinlock.h"
-#include <linux/highmem.h>
+#include "linux/highmem.h"
#include "asm/current.h"
#include "asm/delay.h"
#include "asm/processor.h"
@@ -19,6 +19,7 @@
#include "asm/tlbflush.h"
#include "kern_util.h"
#include "user_util.h"
+#include "mem_user.h"
#include "os.h"
#include "helper.h"
@@ -34,34 +35,66 @@ EXPORT_SYMBOL(task_size);
EXPORT_SYMBOL(flush_tlb_range);
EXPORT_SYMBOL(host_task_size);
EXPORT_SYMBOL(arch_validate);
+EXPORT_SYMBOL(get_kmem_end);
-EXPORT_SYMBOL(region_pa);
-EXPORT_SYMBOL(region_va);
-EXPORT_SYMBOL(phys_mem_map);
-EXPORT_SYMBOL(page_mem_map);
EXPORT_SYMBOL(page_to_phys);
EXPORT_SYMBOL(phys_to_page);
EXPORT_SYMBOL(high_physmem);
EXPORT_SYMBOL(empty_zero_page);
EXPORT_SYMBOL(um_virt_to_phys);
+EXPORT_SYMBOL(__virt_to_page);
+EXPORT_SYMBOL(to_phys);
+EXPORT_SYMBOL(to_virt);
EXPORT_SYMBOL(mode_tt);
EXPORT_SYMBOL(handle_page_fault);
+EXPORT_SYMBOL(find_iomem);
+#ifdef CONFIG_MODE_TT
+EXPORT_SYMBOL(strncpy_from_user_tt);
+EXPORT_SYMBOL(copy_from_user_tt);
+EXPORT_SYMBOL(copy_to_user_tt);
+#endif
+
+#ifdef CONFIG_MODE_SKAS
+EXPORT_SYMBOL(strncpy_from_user_skas);
+EXPORT_SYMBOL(copy_to_user_skas);
+EXPORT_SYMBOL(copy_from_user_skas);
+#endif
+
+EXPORT_SYMBOL(os_stat_fd);
+EXPORT_SYMBOL(os_stat_file);
+EXPORT_SYMBOL(os_access);
+EXPORT_SYMBOL(os_print_error);
+EXPORT_SYMBOL(os_get_exec_close);
+EXPORT_SYMBOL(os_set_exec_close);
EXPORT_SYMBOL(os_getpid);
EXPORT_SYMBOL(os_open_file);
EXPORT_SYMBOL(os_read_file);
EXPORT_SYMBOL(os_write_file);
EXPORT_SYMBOL(os_seek_file);
+EXPORT_SYMBOL(os_lock_file);
+EXPORT_SYMBOL(os_ioctl_generic);
EXPORT_SYMBOL(os_pipe);
EXPORT_SYMBOL(os_file_type);
+EXPORT_SYMBOL(os_file_mode);
+EXPORT_SYMBOL(os_file_size);
+EXPORT_SYMBOL(os_flush_stdout);
EXPORT_SYMBOL(os_close_file);
+EXPORT_SYMBOL(os_set_fd_async);
+EXPORT_SYMBOL(os_set_fd_block);
EXPORT_SYMBOL(helper_wait);
EXPORT_SYMBOL(os_shutdown_socket);
+EXPORT_SYMBOL(os_create_unix_socket);
EXPORT_SYMBOL(os_connect_socket);
+EXPORT_SYMBOL(os_accept_connection);
+EXPORT_SYMBOL(os_rcv_fd);
EXPORT_SYMBOL(run_helper);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(do_gettimeofday);
+EXPORT_SYMBOL(do_settimeofday);
+
/* This is here because UML expands open to sys_open, not to a system
* call instruction.
*/
@@ -90,3 +123,13 @@ EXPORT_SYMBOL(kunmap_atomic);
EXPORT_SYMBOL(kmap_atomic_to_page);
#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/main.c b/arch/um/kernel/main.c
index 38668842523d3..bf832e0f4281f 100644
--- a/arch/um/main.c
+++ b/arch/um/kernel/main.c
@@ -1,13 +1,14 @@
-/*
+/*
* Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <unistd.h>
-#include <stdio.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
+#include <errno.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/user.h>
@@ -22,7 +23,7 @@
#include "choose-mode.h"
#include "uml-config.h"
-/* Set in set_stklim, which is called from main and __wrap_malloc.
+/* Set in set_stklim, which is called from main and __wrap_malloc.
* __wrap_malloc only calls it if main hasn't started.
*/
unsigned long stacksizelim;
@@ -81,7 +82,7 @@ int main(int argc, char **argv, char **envp)
sigset_t mask;
int ret, i;
- /* Enable all signals except SIGIO - in some environments, we can
+ /* Enable all signals except SIGIO - in some environments, we can
* enter with some signals blocked
*/
@@ -96,39 +97,41 @@ int main(int argc, char **argv, char **envp)
/* Allocate memory for thread command lines */
if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
- char padding[THREAD_NAME_LEN] = {
- [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0'
+ char padding[THREAD_NAME_LEN] = {
+ [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0'
};
new_argv = malloc((argc + 2) * sizeof(char*));
if(!new_argv) {
perror("Allocating extended argv");
exit(1);
- }
-
+ }
+
new_argv[0] = argv[0];
new_argv[1] = padding;
-
+
for(i = 2; i <= argc; i++)
new_argv[i] = argv[i - 1];
new_argv[argc + 1] = NULL;
-
+
execvp(new_argv[0], new_argv);
perror("execing with extended args");
exit(1);
- }
+ }
#endif
linux_prog = argv[0];
set_stklim();
- if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){
+ new_argv = malloc((argc + 1) * sizeof(char *));
+ if(new_argv == NULL){
perror("Mallocing argv");
exit(1);
}
for(i=0;i<argc;i++){
- if((new_argv[i] = strdup(argv[i])) == NULL){
+ new_argv[i] = strdup(argv[i]);
+ if(new_argv[i] == NULL){
perror("Mallocing an arg");
exit(1);
}
@@ -141,7 +144,7 @@ int main(int argc, char **argv, char **envp)
do_uml_initcalls();
ret = linux_main(argc, argv);
-
+
/* Reboot */
if(ret){
printf("\n");
@@ -160,10 +163,21 @@ extern void *__real_malloc(int);
void *__wrap_malloc(int size)
{
- if(CAN_KMALLOC())
- return(um_kmalloc(size));
- else
+ void *ret;
+
+ if(!CAN_KMALLOC())
return(__real_malloc(size));
+ else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/
+ ret = um_kmalloc(size);
+ else ret = um_vmalloc(size);
+
+ /* glibc people insist that if malloc fails, errno should be
+ * set by malloc as well. So we do.
+ */
+ if(ret == NULL)
+ errno = ENOMEM;
+
+ return(ret);
}
void *__wrap_calloc(int n, int size)
@@ -177,9 +191,30 @@ void *__wrap_calloc(int n, int size)
extern void __real_free(void *);
+extern unsigned long high_physmem;
+
void __wrap_free(void *ptr)
{
- if(CAN_KMALLOC()) kfree(ptr);
+ unsigned long addr = (unsigned long) ptr;
+
+ /* We need to know how the allocation happened, so it can be correctly
+ * freed. This is done by seeing what region of memory the pointer is
+ * in -
+ * physical memory - kmalloc/kfree
+ * kernel virtual memory - vmalloc/vfree
+ * anywhere else - malloc/free
+ * If kmalloc is not yet possible, then the kernel memory regions
+ * may not be set up yet, and the variables not initialized. So,
+ * free is called.
+ */
+ if(CAN_KMALLOC()){
+ if((addr >= uml_physmem) && (addr <= high_physmem))
+ kfree(ptr);
+ else if((addr >= start_vm) && (addr <= end_vm))
+ vfree(ptr);
+ else
+ __real_free(ptr);
+ }
else __real_free(ptr);
}
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 84a895c2a365d..09add571ccdb5 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -1,74 +1,66 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
-#include "linux/config.h"
-#include "linux/module.h"
-#include "linux/types.h"
+#include "linux/stddef.h"
+#include "linux/kernel.h"
#include "linux/mm.h"
-#include "linux/fs.h"
-#include "linux/init.h"
#include "linux/bootmem.h"
#include "linux/swap.h"
-#include "linux/slab.h"
-#include "linux/vmalloc.h"
#include "linux/highmem.h"
+#include "linux/gfp.h"
#include "asm/page.h"
-#include "asm/pgtable.h"
+#include "asm/fixmap.h"
#include "asm/pgalloc.h"
-#include "asm/bitops.h"
-#include "asm/uaccess.h"
-#include "asm/tlb.h"
#include "user_util.h"
#include "kern_util.h"
-#include "mem_user.h"
-#include "mem.h"
#include "kern.h"
-#include "init.h"
-#include "os.h"
-#include "mode_kern.h"
+#include "mem_user.h"
#include "uml_uaccess.h"
+#include "os.h"
+
+extern char __binary_start;
/* Changed during early boot */
-pgd_t swapper_pg_dir[1024];
-unsigned long high_physmem;
-unsigned long vm_start;
-unsigned long vm_end;
-unsigned long highmem;
unsigned long *empty_zero_page = NULL;
unsigned long *empty_bad_page = NULL;
-
-/* Not modified */
-const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
-
-extern char __init_begin, __init_end;
-extern long physmem_size;
-
-/* Not changed by UML */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-/* Changed during early boot */
+pgd_t swapper_pg_dir[1024];
+unsigned long highmem;
int kmalloc_ok = 0;
-#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1)
-struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL };
-#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1)
-
-/* Changed during early boot */
static unsigned long brk_end;
+void unmap_physmem(void)
+{
+ os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
+}
+
static void map_cb(void *unused)
{
map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
}
-void unmap_physmem(void)
+#ifdef CONFIG_HIGHMEM
+static void setup_highmem(unsigned long highmem_start,
+ unsigned long highmem_len)
{
- os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
-}
+ struct page *page;
+ unsigned long highmem_pfn;
+ int i;
-extern char __binary_start;
+ highmem_start_page = virt_to_page(highmem_start);
+
+ highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
+ for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
+ page = &mem_map[highmem_pfn + i];
+ ClearPageReserved(page);
+ set_bit(PG_highmem, &page->flags);
+ set_page_count(page, 1);
+ __free_page(page);
+ }
+}
+#endif
void mem_init(void)
{
@@ -103,50 +95,15 @@ void mem_init(void)
totalhigh_pages = highmem >> PAGE_SHIFT;
totalram_pages += totalhigh_pages;
num_physpages = totalram_pages;
- max_mapnr = totalram_pages;
max_pfn = totalram_pages;
printk(KERN_INFO "Memory: %luk available\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
kmalloc_ok = 1;
-}
-
-/* Changed during early boot */
-static unsigned long kmem_top = 0;
-
-unsigned long get_kmem_end(void)
-{
- if(kmem_top == 0)
- kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
- return(kmem_top);
-}
-
-void set_kmem_end(unsigned long new)
-{
- kmem_top = new;
-}
#ifdef CONFIG_HIGHMEM
-/* Changed during early boot */
-pte_t *kmap_pte;
-pgprot_t kmap_prot;
-
-EXPORT_SYMBOL(kmap_prot);
-EXPORT_SYMBOL(kmap_pte);
-
-#define kmap_get_fixmap_pte(vaddr) \
- pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
-
-void __init kmap_init(void)
-{
- unsigned long kmap_vstart;
-
- /* cache the first kmap pte */
- kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
- kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
-
- kmap_prot = PAGE_KERNEL;
+ setup_highmem(end_iomem, highmem);
+#endif
}
-#endif /* CONFIG_HIGHMEM */
static void __init fixrange_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
@@ -178,76 +135,24 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
}
}
-int init_maps(struct mem_region *region)
-{
- struct page *p, *map;
- int i, n, len;
-
- if(region == &physmem_region){
- region->mem_map = mem_map;
- return(0);
- }
- else if(region->mem_map != NULL) return(0);
-
- n = region->len >> PAGE_SHIFT;
- len = n * sizeof(struct page);
- if(kmalloc_ok){
- map = kmalloc(len, GFP_KERNEL);
- if(map == NULL) map = vmalloc(len);
- }
- else map = alloc_bootmem_low_pages(len);
-
- if(map == NULL)
- return(-ENOMEM);
- for(i = 0; i < n; i++){
- p = &map[i];
- set_page_count(p, 0);
- SetPageReserved(p);
- INIT_LIST_HEAD(&p->list);
- }
- region->mem_map = map;
- return(0);
-}
+#if CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
-DECLARE_MUTEX(regions_sem);
+#define kmap_get_fixmap_pte(vaddr) \
+ pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
-static int setup_one_range(int fd, char *driver, unsigned long start,
- unsigned long pfn, int len,
- struct mem_region *region)
+void __init kmap_init(void)
{
- int i;
-
- down(&regions_sem);
- for(i = 0; i < NREGIONS; i++){
- if(regions[i] == NULL) break;
- }
- if(i == NREGIONS){
- printk("setup_range : no free regions\n");
- i = -1;
- goto out;
- }
-
- if(fd == -1)
- fd = create_mem_file(len);
+ unsigned long kmap_vstart;
- if(region == NULL){
- region = alloc_bootmem_low_pages(sizeof(*region));
- if(region == NULL)
- panic("Failed to allocating mem_region");
- }
+ /* cache the first kmap pte */
+ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+ kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
- *region = ((struct mem_region) { .driver = driver,
- .start_pfn = pfn,
- .start = start,
- .len = len,
- .fd = fd } );
- regions[i] = region;
- out:
- up(&regions_sem);
- return(i);
+ kmap_prot = PAGE_KERNEL;
}
-#ifdef CONFIG_HIGHMEM
static void init_highmem(void)
{
pgd_t *pgd;
@@ -268,63 +173,20 @@ static void init_highmem(void)
kmap_init();
}
-
-void setup_highmem(unsigned long len)
-{
- struct mem_region *region;
- struct page *page, *map;
- unsigned long phys;
- int i, cur, index;
-
- phys = physmem_size;
- do {
- cur = min(len, (unsigned long) REGION_SIZE);
- i = setup_one_range(-1, NULL, -1, phys >> PAGE_SHIFT, cur,
- NULL);
- if(i == -1){
- printk("setup_highmem - setup_one_range failed\n");
- return;
- }
- region = regions[i];
- index = phys / PAGE_SIZE;
- region->mem_map = &mem_map[index];
-
- map = region->mem_map;
- for(i = 0; i < (cur >> PAGE_SHIFT); i++){
- page = &map[i];
- ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
- set_page_count(page, 1);
- __free_page(page);
- }
- phys += cur;
- len -= cur;
- } while(len > 0);
-}
-#endif
+#endif /* CONFIG_HIGHMEM */
void paging_init(void)
{
- struct mem_region *region;
- unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr;
- int i, index;
+ unsigned long zones_size[MAX_NR_ZONES], vaddr;
+ int i;
empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++)
zones_size[i] = 0;
- zones_size[0] = (high_physmem >> PAGE_SHIFT) -
- (uml_physmem >> PAGE_SHIFT);
+ zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
zones_size[2] = highmem >> PAGE_SHIFT;
free_area_init(zones_size);
- start = phys_region_index(__pa(uml_physmem));
- end = phys_region_index(__pa(high_physmem - 1));
- for(i = start; i <= end; i++){
- region = regions[i];
- index = (region->start - uml_physmem) / PAGE_SIZE;
- region->mem_map = &mem_map[index];
- if(i > start) free_bootmem(__pa(region->start), region->len);
- }
/*
* Fixed mappings, only the page table structure has to be
@@ -335,15 +197,33 @@ void paging_init(void)
#ifdef CONFIG_HIGHMEM
init_highmem();
- setup_highmem(highmem);
#endif
}
-pte_t __bad_page(void)
+struct page *arch_validate(struct page *page, int mask, int order)
{
- clear_page(empty_bad_page);
- return pte_mkdirty(mk_pte((struct page *) empty_bad_page,
- PAGE_SHARED));
+ unsigned long addr, zero = 0;
+ int i;
+
+ again:
+ if(page == NULL) return(page);
+ if(PageHighMem(page)) return(page);
+
+ addr = (unsigned long) page_address(page);
+ for(i = 0; i < (1 << order); i++){
+ current->thread.fault_addr = (void *) addr;
+ if(__do_copy_to_user((void *) addr, &zero,
+ sizeof(zero),
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher)){
+ if(!(mask & __GFP_WAIT)) return(NULL);
+ else break;
+ }
+ addr += PAGE_SIZE;
+ }
+ if(i == (1 << order)) return(page);
+ page = alloc_pages(mask, order);
+ goto again;
}
/* This can't do anything because nothing in the kernel image can be freed
@@ -401,395 +281,6 @@ void show_mem(void)
printk("%d pages swap cached\n", cached);
}
-static int __init uml_mem_setup(char *line, int *add)
-{
- char *retptr;
- physmem_size = memparse(line,&retptr);
- return 0;
-}
-__uml_setup("mem=", uml_mem_setup,
-"mem=<Amount of desired ram>\n"
-" This controls how much \"physical\" memory the kernel allocates\n"
-" for the system. The size is specified as a number followed by\n"
-" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
-" This is not related to the amount of memory in the physical\n"
-" machine. It can be more, and the excess, if it's ever used, will\n"
-" just be swapped out.\n Example: mem=64M\n\n"
-);
-
-struct page *arch_validate(struct page *page, int mask, int order)
-{
- unsigned long addr, zero = 0;
- int i;
-
- again:
- if(page == NULL) return(page);
- if(PageHighMem(page)) return(page);
-
- addr = (unsigned long) page_address(page);
- for(i = 0; i < (1 << order); i++){
- current->thread.fault_addr = (void *) addr;
- if(__do_copy_to_user((void *) addr, &zero,
- sizeof(zero),
- &current->thread.fault_addr,
- &current->thread.fault_catcher)){
- if(!(mask & __GFP_WAIT)) return(NULL);
- else break;
- }
- addr += PAGE_SIZE;
- }
- if(i == (1 << order)) return(page);
- page = alloc_pages(mask, order);
- goto again;
-}
-
-DECLARE_MUTEX(vm_reserved_sem);
-static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved);
-
-/* Static structures, linked in to the list in early boot */
-static struct vm_reserved head = {
- .list = LIST_HEAD_INIT(head.list),
- .start = 0,
- .end = 0xffffffff
-};
-
-static struct vm_reserved tail = {
- .list = LIST_HEAD_INIT(tail.list),
- .start = 0,
- .end = 0xffffffff
-};
-
-void set_usable_vm(unsigned long start, unsigned long end)
-{
- list_add(&head.list, &vm_reserved);
- list_add(&tail.list, &head.list);
- head.end = start;
- tail.start = end;
-}
-
-int reserve_vm(unsigned long start, unsigned long end, void *e)
-
-{
- struct vm_reserved *entry = e, *reserved, *prev;
- struct list_head *ele;
- int err;
-
- down(&vm_reserved_sem);
- list_for_each(ele, &vm_reserved){
- reserved = list_entry(ele, struct vm_reserved, list);
- if(reserved->start >= end) goto found;
- }
- panic("Reserved vm out of range");
- found:
- prev = list_entry(ele->prev, struct vm_reserved, list);
- if(prev->end > start)
- panic("Can't reserve vm");
- if(entry == NULL)
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
- if(entry == NULL){
- printk("reserve_vm : Failed to allocate entry\n");
- err = -ENOMEM;
- goto out;
- }
- *entry = ((struct vm_reserved)
- { .list = LIST_HEAD_INIT(entry->list),
- .start = start,
- .end = end });
- list_add(&entry->list, &prev->list);
- err = 0;
- out:
- up(&vm_reserved_sem);
- return(0);
-}
-
-unsigned long get_vm(unsigned long len)
-{
- struct vm_reserved *this, *next;
- struct list_head *ele;
- unsigned long start;
- int err;
-
- down(&vm_reserved_sem);
- list_for_each(ele, &vm_reserved){
- this = list_entry(ele, struct vm_reserved, list);
- next = list_entry(ele->next, struct vm_reserved, list);
- if((this->start < next->start) &&
- (this->end + len + PAGE_SIZE <= next->start))
- goto found;
- }
- up(&vm_reserved_sem);
- return(0);
- found:
- up(&vm_reserved_sem);
- start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE;
- err = reserve_vm(start, start + len, NULL);
- if(err) return(0);
- return(start);
-}
-
-int nregions(void)
-{
- return(NREGIONS);
-}
-
-void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn,
- unsigned long len, int need_vm, struct mem_region *region,
- void *reserved)
-{
- int i, cur;
-
- do {
- cur = min(len, (unsigned long) REGION_SIZE);
- i = setup_one_range(fd, driver, start, pfn, cur, region);
- region = regions[i];
- if(need_vm && setup_region(region, reserved)){
- kfree(region);
- regions[i] = NULL;
- return;
- }
- start += cur;
- if(pfn != -1) pfn += cur;
- len -= cur;
- } while(len > 0);
-}
-
-struct iomem {
- char *name;
- int fd;
- unsigned long size;
-};
-
-/* iomem regions can only be added on the command line at the moment.
- * Locking will be needed when they can be added via mconsole.
- */
-
-struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] =
- { .name = NULL,
- .fd = -1,
- .size = 0 } };
-
-int num_iomem_regions = 0;
-
-void add_iomem(char *name, int fd, unsigned long size)
-{
- if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))
- return;
- size = (size + PAGE_SIZE - 1) & PAGE_MASK;
- iomem_regions[num_iomem_regions++] =
- ((struct iomem) { .name = name,
- .fd = fd,
- .size = size } );
-}
-
-int setup_iomem(void)
-{
- struct iomem *iomem;
- int i;
-
- for(i = 0; i < num_iomem_regions; i++){
- iomem = &iomem_regions[i];
- setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1,
- NULL, NULL);
- }
- return(0);
-}
-
-__initcall(setup_iomem);
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
-
-/* Changed during early boot */
-static struct mem_region physmem_region;
-static struct vm_reserved physmem_reserved;
-
-void setup_physmem(unsigned long start, unsigned long reserve_end,
- unsigned long len)
-{
- struct mem_region *region = &physmem_region;
- struct vm_reserved *reserved = &physmem_reserved;
- unsigned long cur, pfn = 0;
- int do_free = 1, bootmap_size;
-
- do {
- cur = min(len, (unsigned long) REGION_SIZE);
- if(region == NULL)
- region = alloc_bootmem_low_pages(sizeof(*region));
- if(reserved == NULL)
- reserved = alloc_bootmem_low_pages(sizeof(*reserved));
- if((region == NULL) || (reserved == NULL))
- panic("Couldn't allocate physmem region or vm "
- "reservation\n");
- setup_range(-1, NULL, start, pfn, cur, 1, region, reserved);
-
- if(do_free){
- unsigned long reserve = reserve_end - start;
- int pfn = PFN_UP(__pa(reserve_end));
- int delta = (len - reserve) >> PAGE_SHIFT;
-
- bootmap_size = init_bootmem(pfn, pfn + delta);
- free_bootmem(__pa(reserve_end) + bootmap_size,
- cur - bootmap_size - reserve);
- do_free = 0;
- }
- start += cur;
- pfn += cur >> PAGE_SHIFT;
- len -= cur;
- region = NULL;
- reserved = NULL;
- } while(len > 0);
-}
-
-struct mem_region *phys_region(unsigned long phys)
-{
- unsigned int n = phys_region_index(phys);
-
- if(regions[n] == NULL)
- panic("Physical address in uninitialized region");
- return(regions[n]);
-}
-
-unsigned long phys_offset(unsigned long phys)
-{
- return(phys_addr(phys));
-}
-
-struct page *phys_mem_map(unsigned long phys)
-{
- return((struct page *) phys_region(phys)->mem_map);
-}
-
-struct page *pte_mem_map(pte_t pte)
-{
- return(phys_mem_map(pte_val(pte)));
-}
-
-struct mem_region *page_region(struct page *page, int *index_out)
-{
- int i;
- struct mem_region *region;
- struct page *map;
-
- for(i = 0; i < NREGIONS; i++){
- region = regions[i];
- if(region == NULL) continue;
- map = region->mem_map;
- if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){
- if(index_out != NULL) *index_out = i;
- return(region);
- }
- }
- panic("No region found for page");
- return(NULL);
-}
-
-unsigned long page_to_pfn(struct page *page)
-{
- struct mem_region *region = page_region(page, NULL);
-
- return(region->start_pfn + (page - (struct page *) region->mem_map));
-}
-
-struct mem_region *pfn_to_region(unsigned long pfn, int *index_out)
-{
- struct mem_region *region;
- int i;
-
- for(i = 0; i < NREGIONS; i++){
- region = regions[i];
- if(region == NULL)
- continue;
-
- if((region->start_pfn <= pfn) &&
- (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){
- if(index_out != NULL)
- *index_out = i;
- return(region);
- }
- }
- return(NULL);
-}
-
-struct page *pfn_to_page(unsigned long pfn)
-{
- struct mem_region *region = pfn_to_region(pfn, NULL);
- struct page *mem_map = (struct page *) region->mem_map;
-
- return(&mem_map[pfn - region->start_pfn]);
-}
-
-unsigned long phys_to_pfn(unsigned long p)
-{
- struct mem_region *region = regions[phys_region_index(p)];
-
- return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT));
-}
-
-unsigned long pfn_to_phys(unsigned long pfn)
-{
- int n;
- struct mem_region *region = pfn_to_region(pfn, &n);
-
- return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n));
-}
-
-struct page *page_mem_map(struct page *page)
-{
- return((struct page *) page_region(page, NULL)->mem_map);
-}
-
-extern unsigned long region_pa(void *virt)
-{
- struct mem_region *region;
- unsigned long addr = (unsigned long) virt;
- int i;
-
- for(i = 0; i < NREGIONS; i++){
- region = regions[i];
- if(region == NULL) continue;
- if((region->start <= addr) &&
- (addr <= region->start + region->len))
- return(mk_phys(addr - region->start, i));
- }
- panic("region_pa : no region for virtual address");
- return(0);
-}
-
-extern void *region_va(unsigned long phys)
-{
- return((void *) (phys_region(phys)->start + phys_addr(phys)));
-}
-
-unsigned long page_to_phys(struct page *page)
-{
- int n;
- struct mem_region *region = page_region(page, &n);
- struct page *map = region->mem_map;
- return(mk_phys((page - map) << PAGE_SHIFT, n));
-}
-
-struct page *phys_to_page(unsigned long phys)
-{
- struct page *mem_map;
-
- mem_map = phys_mem_map(phys);
- return(mem_map + (phys_offset(phys) >> PAGE_SHIFT));
-}
-
-static int setup_mem_maps(void)
-{
- struct mem_region *region;
- int i;
-
- for(i = 0; i < NREGIONS; i++){
- region = regions[i];
- if((region != NULL) && (region->fd > 0)) init_maps(region);
- }
- return(0);
-}
-
-__initcall(setup_mem_maps);
-
/*
* Allocate and free page tables.
*/
diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
index d90345b5fd44c..c52744b01d6ca 100644
--- a/arch/um/kernel/mem_user.c
+++ b/arch/um/kernel/mem_user.c
@@ -34,10 +34,9 @@
#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
#include <string.h>
-#include <sys/stat.h>
+#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "kern_util.h"
@@ -47,105 +46,145 @@
#include "init.h"
#include "os.h"
#include "tempfile.h"
+#include "kern_constants.h"
extern struct mem_region physmem_region;
#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
-int create_mem_file(unsigned long len)
+static int create_tmp_file(unsigned long len)
{
- int fd;
+ int fd, err;
char zero;
fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
- if (fchmod(fd, 0777) < 0){
- perror("fchmod");
+ if(fd < 0) {
+ os_print_error(fd, "make_tempfile");
+ exit(1);
+ }
+
+ err = os_mode_fd(fd, 0777);
+ if(err < 0){
+ os_print_error(err, "os_mode_fd");
exit(1);
}
- if(os_seek_file(fd, len) < 0){
- perror("lseek");
+ err = os_seek_file(fd, len);
+ if(err < 0){
+ os_print_error(err, "os_seek_file");
exit(1);
}
zero = 0;
- if(write(fd, &zero, 1) != 1){
- perror("write");
+ err = os_write_file(fd, &zero, 1);
+ if(err != 1){
+ os_print_error(err, "os_write_file");
exit(1);
}
- if(fcntl(fd, F_SETFD, 1) != 0)
- perror("Setting FD_CLOEXEC failed");
+
return(fd);
}
-int setup_region(struct mem_region *region, void *entry)
+static int have_devanon = 0;
+
+void check_devanon(void)
{
- void *loc, *start;
- char *driver;
- int err, offset;
-
- if(region->start != -1){
- err = reserve_vm(region->start,
- region->start + region->len, entry);
- if(err){
- printk("setup_region : failed to reserve "
- "0x%x - 0x%x for driver '%s'\n",
- region->start,
- region->start + region->len,
- region->driver);
- return(-1);
- }
- }
- else region->start = get_vm(region->len);
- if(region->start == 0){
- if(region->driver == NULL) driver = "physmem";
- else driver = region->driver;
- printk("setup_region : failed to find vm for "
- "driver '%s' (length %d)\n", driver, region->len);
- return(-1);
- }
- if(region->start == uml_physmem){
- start = (void *) uml_reserved;
- offset = uml_reserved - uml_physmem;
+ int fd;
+
+ printk("Checking for /dev/anon on the host...");
+ fd = open("/dev/anon", O_RDWR);
+ if(fd < 0){
+ printk("Not available (open failed with errno %d)\n", errno);
+ return;
}
- else {
- start = (void *) region->start;
- offset = 0;
+
+ printk("OK\n");
+ have_devanon = 1;
+}
+
+static int create_anon_file(unsigned long len)
+{
+ void *addr;
+ int fd;
+
+ fd = open("/dev/anon", O_RDWR);
+ if(fd < 0) {
+ os_print_error(fd, "opening /dev/anon");
+ exit(1);
}
- loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_FIXED, region->fd, offset);
- if(loc != start){
- perror("Mapping memory");
+ addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0);
+ if(addr == MAP_FAILED){
+ os_print_error((int) addr, "mapping physmem file");
exit(1);
}
- return(0);
+ munmap(addr, len);
+
+ return(fd);
}
+int create_mem_file(unsigned long len)
+{
+ int err, fd;
+
+ if(have_devanon)
+ fd = create_anon_file(len);
+ else fd = create_tmp_file(len);
+
+ err = os_set_exec_close(fd, 1);
+ if(err < 0)
+ os_print_error(err, "exec_close");
+ return(fd);
+}
+
+struct iomem_region *iomem_regions = NULL;
+int iomem_size = 0;
+
static int __init parse_iomem(char *str, int *add)
{
- struct stat buf;
+ struct iomem_region *new;
+ struct uml_stat buf;
char *file, *driver;
- int fd;
+ int fd, err;
driver = str;
file = strchr(str,',');
if(file == NULL){
- printk("parse_iomem : failed to parse iomem\n");
- return(1);
+ printf("parse_iomem : failed to parse iomem\n");
+ goto out;
}
*file = '\0';
file++;
fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
if(fd < 0){
- printk("parse_iomem - Couldn't open io file, errno = %d\n",
- errno);
- return(1);
+ os_print_error(fd, "parse_iomem - Couldn't open io file");
+ goto out;
}
- if(fstat(fd, &buf) < 0) {
- printk("parse_iomem - cannot fstat file, errno = %d\n", errno);
- return(1);
+
+ err = os_stat_fd(fd, &buf);
+ if(err < 0){
+ os_print_error(err, "parse_iomem - cannot stat_fd file");
+ goto out_close;
}
- add_iomem(driver, fd, buf.st_size);
+
+ new = malloc(sizeof(*new));
+ if(new == NULL){
+ perror("Couldn't allocate iomem_region struct");
+ goto out_close;
+ }
+
+ *new = ((struct iomem_region) { .next = iomem_regions,
+ .driver = driver,
+ .fd = fd,
+ .size = buf.ust_size,
+ .phys = 0,
+ .virt = 0 });
+ iomem_regions = new;
+ iomem_size += new->size + UM_KERN_PAGE_SIZE;
+
return(0);
+ out_close:
+ os_close_file(fd);
+ out:
+ return(1);
}
__uml_setup("iomem=", parse_iomem,
@@ -153,73 +192,20 @@ __uml_setup("iomem=", parse_iomem,
" Configure <file> as an IO memory region named <name>.\n\n"
);
-#ifdef notdef
-int logging = 0;
-int logging_fd = -1;
-
-int logging_line = 0;
-char logging_buf[256];
-
-void log(char *fmt, ...)
-{
- va_list ap;
- struct timeval tv;
- struct openflags flags;
-
- if(logging == 0) return;
- if(logging_fd < 0){
- flags = of_create(of_trunc(of_rdrw(OPENFLAGS())));
- logging_fd = os_open_file("log", flags, 0644);
- }
- gettimeofday(&tv, NULL);
- sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec,
- tv.tv_usec);
- va_start(ap, fmt);
- vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
- va_end(ap);
- write(logging_fd, logging_buf, strlen(logging_buf));
-}
-#endif
-
-int map_memory(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x)
-{
- struct mem_region *region = phys_region(phys);
-
- return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len,
- r, w, x));
-}
-
int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
int must_succeed)
{
- if(os_protect_memory((void *) addr, len, r, w, x) < 0){
+ int err;
+
+ err = os_protect_memory((void *) addr, len, r, w, x);
+ if(err < 0){
if(must_succeed)
- panic("protect failed, errno = %d", errno);
- else return(-errno);
+ panic("protect failed, err = %d", -err);
+ else return(err);
}
return(0);
}
-unsigned long find_iomem(char *driver, unsigned long *len_out)
-{
- struct mem_region *region;
- int i, n;
-
- n = nregions();
- for(i = 0; i < n; i++){
- region = regions[i];
- if(region == NULL) continue;
- if((region->driver != NULL) &&
- !strcmp(region->driver, driver)){
- *len_out = region->len;
- return(region->start);
- }
- }
- *len_out = 0;
- 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
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
new file mode 100644
index 0000000000000..18ed38f8cda41
--- /dev/null
+++ b/arch/um/kernel/physmem.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "linux/ghash.h"
+#include "linux/slab.h"
+#include "linux/vmalloc.h"
+#include "linux/bootmem.h"
+#include "asm/types.h"
+#include "asm/pgtable.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "mode_kern.h"
+#include "mem.h"
+#include "mem_user.h"
+#include "os.h"
+#include "kern.h"
+#include "init.h"
+
+#if 0
+static pgd_t physmem_pgd[PTRS_PER_PGD];
+
+static struct phys_desc *lookup_mapping(void *addr)
+{
+ pgd = &physmem_pgd[pgd_index(addr)];
+ if(pgd_none(pgd))
+ return(NULL);
+
+ pmd = pmd_offset(pgd, addr);
+ if(pmd_none(pmd))
+ return(NULL);
+
+ pte = pte_offset_kernel(pmd, addr);
+ return((struct phys_desc *) pte_val(pte));
+}
+
+static struct add_mapping(void *addr, struct phys_desc *new)
+{
+}
+#endif
+
+#define PHYS_HASHSIZE (8192)
+
+struct phys_desc;
+
+DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc);
+
+struct phys_desc {
+ struct virtmem_ptrs virt_ptrs;
+ int fd;
+ __u64 offset;
+ void *virt;
+ unsigned long phys;
+ struct list_head list;
+};
+
+struct virtmem_table virtmem_hash;
+
+static int virt_cmp(void *virt1, void *virt2)
+{
+ return(virt1 != virt2);
+}
+
+static int virt_hash(void *virt)
+{
+ unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT;
+ return(addr % PHYS_HASHSIZE);
+}
+
+DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp,
+ virt_hash);
+
+LIST_HEAD(descriptor_mappings);
+
+struct desc_mapping {
+ int fd;
+ struct list_head list;
+ struct list_head pages;
+};
+
+static struct desc_mapping *find_mapping(int fd)
+{
+ struct desc_mapping *desc;
+ struct list_head *ele;
+
+ list_for_each(ele, &descriptor_mappings){
+ desc = list_entry(ele, struct desc_mapping, list);
+ if(desc->fd == fd)
+ return(desc);
+ }
+
+ return(NULL);
+}
+
+static struct desc_mapping *descriptor_mapping(int fd)
+{
+ struct desc_mapping *desc;
+
+ desc = find_mapping(fd);
+ if(desc != NULL)
+ return(desc);
+
+ desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+ if(desc == NULL)
+ return(NULL);
+
+ *desc = ((struct desc_mapping)
+ { .fd = fd,
+ .list = LIST_HEAD_INIT(desc->list),
+ .pages = LIST_HEAD_INIT(desc->pages) });
+ list_add(&desc->list, &descriptor_mappings);
+
+ return(desc);
+}
+
+int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
+{
+ struct desc_mapping *fd_maps;
+ struct phys_desc *desc;
+ unsigned long phys;
+ int err;
+
+ fd_maps = descriptor_mapping(fd);
+ if(fd_maps == NULL)
+ return(-ENOMEM);
+
+ phys = __pa(virt);
+ if(find_virtmem_hash(&virtmem_hash, virt) != NULL)
+ panic("Address 0x%p is already substituted\n", virt);
+
+ err = -ENOMEM;
+ desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+ if(desc == NULL)
+ goto out;
+
+ *desc = ((struct phys_desc)
+ { .virt_ptrs = { NULL, NULL },
+ .fd = fd,
+ .offset = offset,
+ .virt = virt,
+ .phys = __pa(virt),
+ .list = LIST_HEAD_INIT(desc->list) });
+ insert_virtmem_hash(&virtmem_hash, desc);
+
+ list_add(&desc->list, &fd_maps->pages);
+
+ virt = (void *) ((unsigned long) virt & PAGE_MASK);
+ err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
+ if(!err)
+ goto out;
+
+ remove_virtmem_hash(&virtmem_hash, desc);
+ kfree(desc);
+ out:
+ return(err);
+}
+
+static int physmem_fd = -1;
+
+static void remove_mapping(struct phys_desc *desc)
+{
+ void *virt = desc->virt;
+ int err;
+
+ remove_virtmem_hash(&virtmem_hash, desc);
+ list_del(&desc->list);
+ kfree(desc);
+
+ err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
+ if(err)
+ panic("Failed to unmap block device page from physical memory, "
+ "errno = %d", -err);
+}
+
+int physmem_remove_mapping(void *virt)
+{
+ struct phys_desc *desc;
+
+ virt = (void *) ((unsigned long) virt & PAGE_MASK);
+ desc = find_virtmem_hash(&virtmem_hash, virt);
+ if(desc == NULL)
+ return(0);
+
+ remove_mapping(desc);
+ return(1);
+}
+
+void physmem_forget_descriptor(int fd)
+{
+ struct desc_mapping *desc;
+ struct phys_desc *page;
+ struct list_head *ele, *next;
+ __u64 offset;
+ void *addr;
+ int err;
+
+ desc = find_mapping(fd);
+ if(desc == NULL)
+ return;
+
+ list_for_each_safe(ele, next, &desc->pages){
+ page = list_entry(ele, struct phys_desc, list);
+ offset = page->offset;
+ addr = page->virt;
+ remove_mapping(page);
+ err = os_seek_file(fd, offset);
+ if(err)
+ panic("physmem_forget_descriptor - failed to seek "
+ "to %lld in fd %d, error = %d\n",
+ offset, fd, -err);
+ err = os_read_file(fd, addr, PAGE_SIZE);
+ if(err < 0)
+ panic("physmem_forget_descriptor - failed to read "
+ "from fd %d to 0x%p, error = %d\n",
+ fd, addr, -err);
+ }
+
+ list_del(&desc->list);
+ kfree(desc);
+}
+
+void arch_free_page(struct page *page, int order)
+{
+ void *virt;
+ int i;
+
+ for(i = 0; i < (1 << order); i++){
+ virt = __va(page_to_phys(page + i));
+ physmem_remove_mapping(virt);
+ }
+}
+
+int is_remapped(void *virt)
+{
+ return(find_virtmem_hash(&virtmem_hash, virt) != NULL);
+}
+
+/* Changed during early boot */
+unsigned long high_physmem;
+
+extern unsigned long physmem_size;
+
+void *to_virt(unsigned long phys)
+{
+ return((void *) uml_physmem + phys);
+}
+
+unsigned long to_phys(void *virt)
+{
+ return(((unsigned long) virt) - uml_physmem);
+}
+
+int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
+{
+ struct page *p, *map;
+ unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
+ unsigned long iomem_len, iomem_pages, total_len, total_pages;
+ int i;
+
+ phys_pages = physmem >> PAGE_SHIFT;
+ phys_len = phys_pages * sizeof(struct page);
+
+ iomem_pages = iomem >> PAGE_SHIFT;
+ iomem_len = iomem_pages * sizeof(struct page);
+
+ highmem_pages = highmem >> PAGE_SHIFT;
+ highmem_len = highmem_pages * sizeof(struct page);
+
+ total_pages = phys_pages + iomem_pages + highmem_pages;
+ total_len = phys_len + iomem_pages + highmem_len;
+
+ if(kmalloc_ok){
+ map = kmalloc(total_len, GFP_KERNEL);
+ if(map == NULL)
+ map = vmalloc(total_len);
+ }
+ else map = alloc_bootmem_low_pages(total_len);
+
+ if(map == NULL)
+ return(-ENOMEM);
+
+ for(i = 0; i < total_pages; i++){
+ p = &map[i];
+ set_page_count(p, 0);
+ SetPageReserved(p);
+ INIT_LIST_HEAD(&p->lru);
+ }
+
+ mem_map = map;
+ max_mapnr = total_pages;
+ return(0);
+}
+
+struct page *phys_to_page(const unsigned long phys)
+{
+ return(&mem_map[phys >> PAGE_SHIFT]);
+}
+
+struct page *__virt_to_page(const unsigned long virt)
+{
+ return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
+}
+
+unsigned long page_to_phys(struct page *page)
+{
+ return((page - mem_map) << PAGE_SHIFT);
+}
+
+pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+ pte_t pte;
+
+ pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot);
+ if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte));
+ return(pte);
+}
+
+/* Changed during early boot */
+static unsigned long kmem_top = 0;
+
+unsigned long get_kmem_end(void)
+{
+ if(kmem_top == 0)
+ kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
+ return(kmem_top);
+}
+
+void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
+ int r, int w, int x)
+{
+ __u64 offset;
+ int fd, err;
+
+ fd = phys_mapping(phys, &offset);
+ err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
+ if(err)
+ panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
+ "err = %d\n", virt, fd, offset, len, r, w, x, err);
+}
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+
+void setup_physmem(unsigned long start, unsigned long reserve_end,
+ unsigned long len, unsigned long highmem)
+{
+ unsigned long reserve = reserve_end - start;
+ int pfn = PFN_UP(__pa(reserve_end));
+ int delta = (len - reserve) >> PAGE_SHIFT;
+ int err, offset, bootmap_size;
+
+ physmem_fd = create_mem_file(len + highmem);
+
+ offset = uml_reserved - uml_physmem;
+ err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
+ len - offset, 1, 1, 0);
+ if(err < 0){
+ os_print_error(err, "Mapping memory");
+ exit(1);
+ }
+
+ bootmap_size = init_bootmem(pfn, pfn + delta);
+ free_bootmem(__pa(reserve_end) + bootmap_size,
+ len - bootmap_size - reserve);
+}
+
+int phys_mapping(unsigned long phys, __u64 *offset_out)
+{
+ struct phys_desc *desc = find_virtmem_hash(&virtmem_hash,
+ __va(phys & PAGE_MASK));
+ int fd = -1;
+
+ if(desc != NULL){
+ fd = desc->fd;
+ *offset_out = desc->offset;
+ }
+ else if(phys < physmem_size){
+ fd = physmem_fd;
+ *offset_out = phys;
+ }
+ else if(phys < __pa(end_iomem)){
+ struct iomem_region *region = iomem_regions;
+
+ while(region != NULL){
+ if((phys >= region->phys) &&
+ (phys < region->phys + region->size)){
+ fd = region->fd;
+ *offset_out = phys - region->phys;
+ break;
+ }
+ region = region->next;
+ }
+ }
+ else if(phys < __pa(end_iomem) + highmem){
+ fd = physmem_fd;
+ *offset_out = phys - iomem_size;
+ }
+
+ return(fd);
+}
+
+static int __init uml_mem_setup(char *line, int *add)
+{
+ char *retptr;
+ physmem_size = memparse(line,&retptr);
+ return 0;
+}
+__uml_setup("mem=", uml_mem_setup,
+"mem=<Amount of desired ram>\n"
+" This controls how much \"physical\" memory the kernel allocates\n"
+" for the system. The size is specified as a number followed by\n"
+" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
+" This is not related to the amount of memory in the host. It can\n"
+" be more, and the excess, if it's ever used, will just be swapped out.\n"
+" Example: mem=64M\n\n"
+);
+
+unsigned long find_iomem(char *driver, unsigned long *len_out)
+{
+ struct iomem_region *region = iomem_regions;
+
+ while(region != NULL){
+ if(!strcmp(region->driver, driver)){
+ *len_out = region->size;
+ return(region->virt);
+ }
+ }
+
+ return(0);
+}
+
+int setup_iomem(void)
+{
+ struct iomem_region *region = iomem_regions;
+ unsigned long iomem_start = high_physmem + PAGE_SIZE;
+ int err;
+
+ while(region != NULL){
+ err = os_map_memory((void *) iomem_start, region->fd, 0,
+ region->size, 1, 1, 0);
+ if(err)
+ printk("Mapping iomem region for driver '%s' failed, "
+ "errno = %d\n", region->driver, -err);
+ else {
+ region->virt = iomem_start;
+ region->phys = __pa(region->virt);
+ }
+
+ iomem_start += region->size + PAGE_SIZE;
+ region = region->next;
+ }
+
+ return(0);
+}
+
+__initcall(setup_iomem);
+
+/*
+ * 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/process.c b/arch/um/kernel/process.c
index 4c3aa45359eb7..ff8f72736feca 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -9,18 +9,17 @@
#include <sched.h>
#include <errno.h>
#include <stdarg.h>
-#include <fcntl.h>
#include <stdlib.h>
#include <setjmp.h>
#include <sys/time.h>
#include <sys/ptrace.h>
-#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <asm/ptrace.h>
#include <asm/sigcontext.h>
#include <asm/unistd.h>
#include <asm/page.h>
+#include <asm/user.h>
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
@@ -58,7 +57,11 @@ void init_new_thread_signals(int altstack)
{
int flags = altstack ? SA_ONSTACK : 0;
- set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
+ /* NODEFER is set here because SEGV isn't turned back on when the
+ * handler is ready to receive signals. This causes any segfault
+ * during a copy_user to kill the process because the fault is blocked.
+ */
+ set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
@@ -72,7 +75,6 @@ void init_new_thread_signals(int altstack)
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGUSR2, (__sighandler_t) sig_handler,
SA_NOMASK | flags, -1);
- (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0);
signal(SIGHUP, SIG_IGN);
init_irq_signals(altstack);
@@ -122,12 +124,17 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
/* Start the process and wait for it to kill itself */
new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
- if(new_pid < 0) return(-errno);
- while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ;
- if(err < 0) panic("Waiting for outer trampoline failed - errno = %d",
- errno);
+ if(new_pid < 0)
+ return(new_pid);
+
+ CATCH_EINTR(err = waitpid(new_pid, &status, 0));
+ if(err < 0)
+ panic("Waiting for outer trampoline failed - errno = %d",
+ errno);
+
if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
- panic("outer trampoline didn't exit with SIGKILL");
+ panic("outer trampoline didn't exit with SIGKILL, "
+ "status = %d", status);
return(arg.pid);
}
@@ -138,7 +145,7 @@ void suspend_new_thread(int fd)
os_stop_process(os_getpid());
- if(read(fd, &c, sizeof(c)) != sizeof(c))
+ if(os_read_file(fd, &c, sizeof(c)) != sizeof(c))
panic("read failed in suspend_new_thread");
}
@@ -168,7 +175,7 @@ static int start_ptraced_child(void **stack_out)
pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
if(pid < 0)
panic("check_ptrace : clone failed, errno = %d", errno);
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
@@ -185,7 +192,7 @@ static void stop_ptraced_child(int pid, void *stack, int exitcode)
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d", errno);
- n = waitpid(pid, &status, 0);
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode))
panic("check_ptrace : child exited with status 0x%x", status);
@@ -193,6 +200,66 @@ static void stop_ptraced_child(int pid, void *stack, int exitcode)
panic("check_ptrace : munmap failed, errno = %d", errno);
}
+static int force_sysemu_disabled = 0;
+
+static int __init nosysemu_cmd_param(char *str, int* add)
+{
+ force_sysemu_disabled = 1;
+ return 0;
+}
+
+__uml_setup("nosysemu", nosysemu_cmd_param,
+ "nosysemu\n"
+ " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
+ " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
+ " behaviour of ptrace() and helps reducing host context switch rate.\n"
+ " To make it working, you need a kernel patch for your host, too.\n"
+ " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n");
+
+static void __init check_sysemu(void)
+{
+ void *stack;
+ int pid, n, status;
+
+ if (mode_tt)
+ return;
+
+ printk("Checking syscall emulation patch for ptrace...");
+ sysemu_supported = 0;
+ pid = start_ptraced_child(&stack);
+ if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) {
+ struct user_regs_struct regs;
+
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+ if (n < 0)
+ panic("check_ptrace : wait failed, errno = %d", errno);
+ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+ panic("check_ptrace : expected SIGTRAP, "
+ "got status = %d", status);
+
+ if (ptrace(PTRACE_GETREGS, pid, 0, &regs) < 0)
+ panic("check_ptrace : failed to read child "
+ "registers, errno = %d", errno);
+ regs.orig_eax = pid;
+ if (ptrace(PTRACE_SETREGS, pid, 0, &regs) < 0)
+ panic("check_ptrace : failed to modify child "
+ "registers, errno = %d", errno);
+
+ stop_ptraced_child(pid, stack, 0);
+
+ sysemu_supported = 1;
+ printk("found\n");
+ }
+ else
+ {
+ stop_ptraced_child(pid, stack, 1);
+ sysemu_supported = 0;
+ printk("missing\n");
+ }
+
+ set_using_sysemu(!force_sysemu_disabled);
+}
+
void __init check_ptrace(void)
{
void *stack;
@@ -205,7 +272,7 @@ void __init check_ptrace(void)
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d",
errno);
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
@@ -225,6 +292,7 @@ void __init check_ptrace(void)
}
stop_ptraced_child(pid, stack, 0);
printk("OK\n");
+ check_sysemu();
}
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
@@ -233,7 +301,7 @@ int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
int n;
*jmp_ptr = &buf;
- n = setjmp(buf);
+ n = sigsetjmp(buf, 1);
if(n != 0)
return(n);
(*fn)(arg);
@@ -273,7 +341,7 @@ int can_do_skas(void)
stop_ptraced_child(pid, stack, 1);
printf("Checking for /proc/mm...");
- if(access("/proc/mm", W_OK)){
+ if(os_access("/proc/mm", OS_ACC_W_OK) < 0){
printf("not found\n");
ret = 0;
}
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index e17600a9b3876..864a5b8293157 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -16,6 +16,8 @@
#include "linux/module.h"
#include "linux/init.h"
#include "linux/capability.h"
+#include "linux/vmalloc.h"
+#include "linux/spinlock.h"
#include "asm/unistd.h"
#include "asm/mman.h"
#include "asm/segment.h"
@@ -23,7 +25,6 @@
#include "asm/pgtable.h"
#include "asm/processor.h"
#include "asm/tlbflush.h"
-#include "asm/spinlock.h"
#include "asm/uaccess.h"
#include "asm/user.h"
#include "user_util.h"
@@ -52,17 +53,12 @@ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
struct task_struct *get_task(int pid, int require)
{
- struct task_struct *task, *ret;
+ struct task_struct *ret;
- ret = NULL;
read_lock(&tasklist_lock);
- for_each_process(task){
- if(task->pid == pid){
- ret = task;
- break;
- }
- }
+ ret = find_task_by_pid(pid);
read_unlock(&tasklist_lock);
+
if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
return(ret);
}
@@ -95,7 +91,8 @@ unsigned long alloc_stack(int order, int atomic)
int flags = GFP_KERNEL;
if(atomic) flags |= GFP_ATOMIC;
- if((page = __get_free_pages(flags, order)) == 0)
+ page = __get_free_pages(flags, order);
+ if(page == 0)
return(0);
stack_protections(page);
return(page);
@@ -103,22 +100,25 @@ unsigned long alloc_stack(int order, int atomic)
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
- struct task_struct *p;
+ int pid;
current->thread.request.u.thread.proc = fn;
current->thread.request.u.thread.arg = arg;
- p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL);
- if(IS_ERR(p)) panic("do_fork failed in kernel_thread");
- return(p->pid);
+ pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL,
+ NULL);
+ if(pid < 0)
+ panic("do_fork failed in kernel_thread, errno = %d", pid);
+ return(pid);
}
void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
- unsigned cpu = smp_processor_id();
+ int cpu = smp_processor_id();
+
if (prev != next)
- clear_bit(cpu, &prev->cpu_vm_mask);
- set_bit(cpu, &next->cpu_vm_mask);
+ cpu_clear(cpu, prev->cpu_vm_mask);
+ cpu_set(cpu, next->cpu_vm_mask);
}
void set_current(void *t)
@@ -129,7 +129,7 @@ void set_current(void *t)
{ external_pid(task), task });
}
-void *switch_to(void *prev, void *next, void *last)
+void *_switch_to(void *prev, void *next, void *last)
{
return(CHOOSE_MODE(switch_to_tt(prev, next),
switch_to_skas(prev, next)));
@@ -149,7 +149,7 @@ void release_thread(struct task_struct *task)
void exit_thread(void)
{
CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
- unprotect_stack((unsigned long) current->thread_info);
+ unprotect_stack((unsigned long) current_thread);
}
void *get_current(void)
@@ -157,6 +157,10 @@ void *get_current(void)
return(current);
}
+void prepare_to_copy(struct task_struct *tsk)
+{
+}
+
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
unsigned long stack_top, struct task_struct * p,
struct pt_regs *regs)
@@ -190,7 +194,7 @@ int current_pid(void)
void default_idle(void)
{
- idle_timer();
+ uml_idle_timer();
atomic_inc(&init_mm.mm_count);
current->mm = &init_mm;
@@ -299,6 +303,11 @@ void *um_kmalloc_atomic(int size)
return(kmalloc(size, GFP_ATOMIC));
}
+void *um_vmalloc(int size)
+{
+ return(vmalloc(size));
+}
+
unsigned long get_fault_addr(void)
{
return((unsigned long) current->thread.fault_addr);
@@ -367,10 +376,15 @@ int clear_user_proc(void *buf, int size)
return(clear_user(buf, size));
}
+int strlen_user_proc(char *str)
+{
+ return(strlen_user(str));
+}
+
int smp_sigio_handler(void)
{
#ifdef CONFIG_SMP
- int cpu = current->thread_info->cpu;
+ int cpu = current_thread->cpu;
IPI_handler(cpu);
if(cpu != 0)
return(1);
@@ -385,7 +399,7 @@ int um_in_interrupt(void)
int cpu(void)
{
- return(current->thread_info->cpu);
+ return(current_thread->cpu);
}
/*
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index c68c937f6812b..9d2c9eb8c5033 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -24,11 +24,6 @@ void ptrace_disable(struct task_struct *child)
{
}
-extern long do_mmap2(struct task_struct *task, unsigned long addr,
- unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long fd,
- unsigned long pgoff);
-
int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -302,8 +297,17 @@ int sys_ptrace(long request, long pid, long addr, long data)
return ret;
}
-void syscall_trace(void)
+void syscall_trace(union uml_pt_regs *regs, int entryexit)
{
+ if (unlikely(current->audit_context)) {
+ if (!entryexit)
+ audit_syscall_entry(current, regs->orig_eax,
+ regs->ebx, regs->ecx,
+ regs->edx, regs->esi);
+ else
+ audit_syscall_exit(current, regs->eax);
+ }
+
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
if (!(current->ptrace & PT_PTRACED))
@@ -311,11 +315,8 @@ void syscall_trace(void)
/* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
- current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0);
- current->state = TASK_STOPPED;
- notify_parent(current, SIGCHLD);
- schedule();
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0));
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 3e4ab2963be5a..207f89d749080 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -15,6 +15,7 @@
#ifdef CONFIG_SMP
static void kill_idlers(int me)
{
+#ifdef CONFIG_MODE_TT
struct task_struct *p;
int i;
@@ -23,6 +24,7 @@ static void kill_idlers(int me)
if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
os_kill_process(p->thread.mode.tt.extern_pid, 0);
}
+#endif
}
#endif
diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
index 02272e6236147..92658eaa4e4dd 100644
--- a/arch/um/kernel/sigio_kern.c
+++ b/arch/um/kernel/sigio_kern.c
@@ -6,18 +6,21 @@
#include "linux/kernel.h"
#include "linux/list.h"
#include "linux/slab.h"
-#include "asm/irq.h"
+#include "linux/signal.h"
+#include "linux/interrupt.h"
#include "init.h"
#include "sigio.h"
#include "irq_user.h"
+#include "irq_kern.h"
/* Protected by sigio_lock() called from write_sigio_workaround */
static int sigio_irq_fd = -1;
-void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
{
read_sigio_fd(sigio_irq_fd);
reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
+ return(IRQ_HANDLED);
}
int write_sigio_irq(int fd)
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
index b5ce13d55cd52..de4fcb279d6e1 100644
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -7,7 +7,6 @@
#include <stdlib.h>
#include <termios.h>
#include <pty.h>
-#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
@@ -17,6 +16,7 @@
#include "init.h"
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "sigio.h"
#include "helper.h"
#include "os.h"
@@ -26,7 +26,7 @@ int pty_output_sigio = 0;
int pty_close_sigio = 0;
/* Used as a flag during SIGIO testing early in boot */
-static int got_sigio = 0;
+static volatile int got_sigio = 0;
void __init handler(int sig)
{
@@ -45,19 +45,18 @@ static void openpty_cb(void *arg)
info->err = 0;
if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
- info->err = errno;
+ info->err = -errno;
}
void __init check_one_sigio(void (*proc)(int, int))
{
struct sigaction old, new;
- struct termios tt;
struct openpty_arg pty = { .master = -1, .slave = -1 };
- int master, slave, flags;
+ int master, slave, err;
initial_thread_cb(openpty_cb, &pty);
if(pty.err){
- printk("openpty failed, errno = %d\n", pty.err);
+ printk("openpty failed, errno = %d\n", -pty.err);
return;
}
@@ -69,23 +68,13 @@ void __init check_one_sigio(void (*proc)(int, int))
return;
}
- if(tcgetattr(master, &tt) < 0)
- panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
- cfmakeraw(&tt);
- if(tcsetattr(master, TCSADRAIN, &tt) < 0)
- panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
+ err = __raw(master, 1, 0); //Not now, but complain so we now where we failed.
+ if (err < 0)
+ panic("check_sigio : __raw failed, errno = %d\n", -err);
- if((flags = fcntl(master, F_GETFL)) < 0)
- panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno);
-
- if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
- (fcntl(master, F_SETOWN, os_getpid()) < 0))
- panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, "
- "errno = %d\n", errno);
-
- if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
- panic("check_sigio : fcntl F_SETFL failed, errno = %d\n",
- errno);
+ err = os_sigio_async(master, slave);
+ if(err < 0)
+ panic("tty_fds : sigio_async failed, err = %d\n", -err);
if(sigaction(SIGIO, NULL, &old) < 0)
panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
@@ -97,8 +86,8 @@ void __init check_one_sigio(void (*proc)(int, int))
got_sigio = 0;
(*proc)(master, slave);
- close(master);
- close(slave);
+ os_close_file(master);
+ os_close_file(slave);
if(sigaction(SIGIO, &old, NULL) < 0)
panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
@@ -112,25 +101,25 @@ static void tty_output(int master, int slave)
printk("Checking that host ptys support output SIGIO...");
memset(buf, 0, sizeof(buf));
- while(write(master, buf, sizeof(buf)) > 0) ;
+
+ while(os_write_file(master, buf, sizeof(buf)) > 0) ;
if(errno != EAGAIN)
panic("check_sigio : write failed, errno = %d\n", errno);
-
- while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+ while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
if(got_sigio){
printk("Yes\n");
pty_output_sigio = 1;
}
- else if(errno == EAGAIN) printk("No, enabling workaround\n");
- else panic("check_sigio : read failed, errno = %d\n", errno);
+ else if(n == -EAGAIN) printk("No, enabling workaround\n");
+ else panic("check_sigio : read failed, err = %d\n", n);
}
static void tty_close(int master, int slave)
{
printk("Checking that host ptys support SIGIO on close...");
- close(slave);
+ os_close_file(slave);
if(got_sigio){
printk("Yes\n");
pty_close_sigio = 1;
@@ -140,7 +129,8 @@ static void tty_close(int master, int slave)
void __init check_sigio(void)
{
- if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){
+ if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
+ (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
printk("No pseudo-terminals available - skipping pty SIGIO "
"check\n");
return;
@@ -201,11 +191,10 @@ static int write_sigio_thread(void *unused)
p = &fds->poll[i];
if(p->revents == 0) continue;
if(p->fd == sigio_private[1]){
- n = read(sigio_private[1], &c, sizeof(c));
+ n = os_read_file(sigio_private[1], &c, sizeof(c));
if(n != sizeof(c))
printk("write_sigio_thread : "
- "read failed, errno = %d\n",
- errno);
+ "read failed, err = %d\n", -n);
tmp = current_poll;
current_poll = next_poll;
next_poll = tmp;
@@ -218,10 +207,10 @@ static int write_sigio_thread(void *unused)
(fds->used - i) * sizeof(*fds->poll));
}
- n = write(respond_fd, &c, sizeof(c));
+ n = os_write_file(respond_fd, &c, sizeof(c));
if(n != sizeof(c))
printk("write_sigio_thread : write failed, "
- "errno = %d\n", errno);
+ "err = %d\n", -n);
}
}
}
@@ -252,15 +241,15 @@ static void update_thread(void)
char c;
flags = set_signals(0);
- n = write(sigio_private[0], &c, sizeof(c));
+ n = os_write_file(sigio_private[0], &c, sizeof(c));
if(n != sizeof(c)){
- printk("update_thread : write failed, errno = %d\n", errno);
+ printk("update_thread : write failed, err = %d\n", -n);
goto fail;
}
- n = read(sigio_private[0], &c, sizeof(c));
+ n = os_read_file(sigio_private[0], &c, sizeof(c));
if(n != sizeof(c)){
- printk("update_thread : read failed, errno = %d\n", errno);
+ printk("update_thread : read failed, err = %d\n", -n);
goto fail;
}
@@ -271,10 +260,10 @@ static void update_thread(void)
if(write_sigio_pid != -1)
os_kill_process(write_sigio_pid, 1);
write_sigio_pid = -1;
- close(sigio_private[0]);
- close(sigio_private[1]);
- close(write_sigio_fds[0]);
- close(write_sigio_fds[1]);
+ os_close_file(sigio_private[0]);
+ os_close_file(sigio_private[1]);
+ os_close_file(write_sigio_fds[0]);
+ os_close_file(write_sigio_fds[1]);
sigio_unlock();
set_signals(flags);
}
@@ -369,15 +358,15 @@ void write_sigio_workaround(void)
goto out;
err = os_pipe(write_sigio_fds, 1, 1);
- if(err){
+ if(err < 0){
printk("write_sigio_workaround - os_pipe 1 failed, "
- "errno = %d\n", -err);
+ "err = %d\n", -err);
goto out;
}
err = os_pipe(sigio_private, 1, 1);
- if(err){
+ if(err < 0){
printk("write_sigio_workaround - os_pipe 2 failed, "
- "errno = %d\n", -err);
+ "err = %d\n", -err);
goto out_close1;
}
if(setup_initial_poll(sigio_private[1]))
@@ -399,11 +388,11 @@ void write_sigio_workaround(void)
os_kill_process(write_sigio_pid, 1);
write_sigio_pid = -1;
out_close2:
- close(sigio_private[0]);
- close(sigio_private[1]);
+ os_close_file(sigio_private[0]);
+ os_close_file(sigio_private[1]);
out_close1:
- close(write_sigio_fds[0]);
- close(write_sigio_fds[1]);
+ os_close_file(write_sigio_fds[0]);
+ os_close_file(write_sigio_fds[1]);
sigio_unlock();
}
@@ -412,10 +401,16 @@ int read_sigio_fd(int fd)
int n;
char c;
- n = read(fd, &c, sizeof(c));
+ n = os_read_file(fd, &c, sizeof(c));
if(n != sizeof(c)){
- printk("read_sigio_fd - read failed, errno = %d\n", errno);
- return(-errno);
+ if(n < 0) {
+ printk("read_sigio_fd - read failed, err = %d\n", -n);
+ return(n);
+ }
+ else {
+ printk("read_sigio_fd - short read, bytes = %d\n", n);
+ return(-EIO);
+ }
}
return(n);
}
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
index 6e13847edb758..23aefcbea7a24 100644
--- a/arch/um/kernel/signal_kern.c
+++ b/arch/um/kernel/signal_kern.c
@@ -31,17 +31,6 @@
EXPORT_SYMBOL(block_signals);
EXPORT_SYMBOL(unblock_signals);
-static void force_segv(int sig)
-{
- if(sig == SIGSEGV){
- struct k_sigaction *ka;
-
- ka = &current->sig->action[SIGSEGV - 1];
- ka->sa.sa_handler = SIG_DFL;
- }
- force_sig(SIGSEGV, current);
-}
-
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
@@ -60,10 +49,10 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
int err, ret;
ret = 0;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
switch(error){
case -ERESTART_RESTARTBLOCK:
- current_thread_info()->restart_block.fn =
- do_no_restart_syscall;
case -ERESTARTNOHAND:
ret = -EINTR;
break;
@@ -124,27 +113,27 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
return(0);
segv:
- force_segv(signr);
+ force_sigsegv(signr, current);
return(1);
}
static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
{
+ struct k_sigaction ka_copy;
siginfo_t info;
- struct k_sigaction *ka;
int err, sig;
if (!oldset)
oldset = &current->blocked;
- sig = get_signal_to_deliver(&info, regs, NULL);
+ sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL);
if(sig == 0)
return(0);
/* Whee! Actually deliver the signal. */
- ka = &current->sig->action[sig -1 ];
- err = handle_signal(regs, sig, ka, &info, oldset, error);
- if(!err) return(1);
+ err = handle_signal(regs, sig, &ka_copy, &info, oldset, error);
+ if(!err)
+ return(1);
/* Did we come from a system call? */
if(PT_REGS_SYSCALL_NR(regs) >= 0){
@@ -201,7 +190,7 @@ int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
}
}
-int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
{
sigset_t saveset, newset;
@@ -227,20 +216,59 @@ int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
}
}
+int sys_sigaction(int sig, const struct old_sigaction __user *act,
+ struct old_sigaction __user *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
+}
+
+extern int userspace_pid[];
+
static int copy_sc_from_user(struct pt_regs *to, void *from,
struct arch_frame_data *arch)
{
int ret;
ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
- copy_sc_from_user_skas(&to->regs, from));
+ copy_sc_from_user_skas(userspace_pid[0],
+ &to->regs, from));
return(ret);
}
int sys_sigreturn(struct pt_regs regs)
{
- void *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
- void *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
+ void __user *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
+ void __user *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
spin_lock_irq(&current->sighand->siglock);
@@ -257,8 +285,8 @@ int sys_sigreturn(struct pt_regs regs)
int sys_rt_sigreturn(struct pt_regs regs)
{
- struct ucontext *uc = sp_to_uc(PT_REGS_SP(&current->thread.regs));
- void *fp;
+ unsigned long sp = PT_REGS_SP(&current->thread.regs);
+ struct ucontext __user *uc = sp_to_uc(sp);
int sig_size = _NSIG_WORDS * sizeof(unsigned long);
spin_lock_irq(&current->sighand->siglock);
@@ -266,7 +294,6 @@ int sys_rt_sigreturn(struct pt_regs regs)
sigdelsetmask(&current->blocked, ~_BLOCKABLE);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext));
copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
&signal_frame_si.common.arch);
return(PT_REGS_SYSCALL_RET(&current->thread.regs));
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index 72c79956f6a6a..bc53682e03333 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -5,20 +5,24 @@
obj-y = exec_kern.o exec_user.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 \
- sys-$(SUBARCH)/
+ uaccess.o sys-$(SUBARCH)/
+
+hostprogs-y := util/mk_ptregs
+clean-files := include/skas_ptregs.h
USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-include/skas_ptregs.h : util/mk_ptregs
- util/mk_ptregs > $@
-
-util/mk_ptregs :
- $(MAKE) -C util
+$(TOPDIR)/arch/um/include/skas_ptregs.h : $(src)/util/mk_ptregs
+ @echo -n ' Generating $@'
+ @$< > $@.tmp
+ @if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ echo ' (unchanged)'; \
+ rm -f $@.tmp; \
+ else \
+ echo ' (updated)'; \
+ mv -f $@.tmp $@; \
+ fi
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-clean :
- $(MAKE) -C util clean
- $(RM) -f include/skas_ptregs.h
diff --git a/arch/um/kernel/skas/exec_user.c b/arch/um/kernel/skas/exec_user.c
index c9942b6fc79b5..d50633a709211 100644
--- a/arch/um/kernel/skas/exec_user.c
+++ b/arch/um/kernel/skas/exec_user.c
@@ -11,6 +11,7 @@
#include <sys/ptrace.h>
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "os.h"
#include "time_user.h"
@@ -26,7 +27,7 @@ static int user_thread_tramp(void *arg)
int user_thread(unsigned long stack, int flags)
{
- int pid, status;
+ int pid, status, err;
pid = clone(user_thread_tramp, (void *) stack_sp(stack),
flags | CLONE_FILES | SIGCHLD, NULL);
@@ -35,7 +36,8 @@ int user_thread(unsigned long stack, int flags)
return(pid);
}
- if(waitpid(pid, &status, WUNTRACED) < 0){
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+ if(err < 0){
printk("user_thread - waitpid failed, errno = %d\n", errno);
return(-errno);
}
diff --git a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h
index 7516206cc2991..285edc50a27fb 100644
--- a/arch/um/kernel/skas/include/mode.h
+++ b/arch/um/kernel/skas/include/mode.h
@@ -12,14 +12,16 @@ extern unsigned long exec_fpx_regs[];
extern int have_fpx_regs;
extern void user_time_init_skas(void);
-extern int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr);
-extern int copy_sc_to_user_skas(void *to_ptr, void *fp,
+extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs,
+ void *from_ptr);
+extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp,
union uml_pt_regs *regs,
unsigned long fault_addr, int fault_type);
extern void sig_handler_common_skas(int sig, void *sc_ptr);
extern void halt_skas(void);
extern void reboot_skas(void);
extern void kill_off_processes_skas(void);
+extern int is_skas_winch(int pid, int fd, void *data);
#endif
diff --git a/arch/um/kernel/skas/include/ptrace-skas.h b/arch/um/kernel/skas/include/ptrace-skas.h
index f5c5268cc4925..be043e8f7e78a 100644
--- a/arch/um/kernel/skas/include/ptrace-skas.h
+++ b/arch/um/kernel/skas/include/ptrace-skas.h
@@ -10,6 +10,16 @@
#ifdef UML_CONFIG_MODE_SKAS
+/* syscall emulation path in ptrace */
+
+#ifndef PTRACE_SYSEMU
+#define PTRACE_SYSEMU 31
+#endif
+
+void set_using_sysemu(int value);
+int get_using_sysemu(void);
+extern int sysemu_supported;
+
#include "skas_ptregs.h"
#define HOST_FRAME_SIZE 17
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index d9614f6cd7ea1..0bbc97540815e 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -8,7 +8,7 @@
#include "sysdep/ptrace.h"
-extern int userspace_pid;
+extern int userspace_pid[];
extern void switch_threads(void *me, void *next);
extern void thread_wait(void *sw, void *fb);
@@ -32,7 +32,7 @@ extern int singlestepping_skas(void);
extern int new_mm(int from);
extern void save_registers(union uml_pt_regs *regs);
extern void restore_registers(union uml_pt_regs *regs);
-extern void start_userspace(void);
+extern void start_userspace(int cpu);
extern void init_registers(int pid);
#endif
diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h
index d28c4b1de07e7..0d6f30bf718f0 100644
--- a/arch/um/kernel/skas/include/uaccess.h
+++ b/arch/um/kernel/skas/include/uaccess.h
@@ -6,20 +6,12 @@
#ifndef __SKAS_UACCESS_H
#define __SKAS_UACCESS_H
-#include "linux/string.h"
-#include "linux/sched.h"
-#include "linux/err.h"
-#include "asm/processor.h"
-#include "asm/pgtable.h"
#include "asm/errno.h"
-#include "asm/current.h"
-#include "asm/a.out.h"
-#include "kern_util.h"
#define access_ok_skas(type, addr, size) \
((segment_eq(get_fs(), KERNEL_DS)) || \
(((unsigned long) (addr) < TASK_SIZE) && \
- ((unsigned long) (addr) + (size) < TASK_SIZE)))
+ ((unsigned long) (addr) + (size) <= TASK_SIZE)))
static inline int verify_area_skas(int type, const void * addr,
unsigned long size)
@@ -27,197 +19,12 @@ static inline int verify_area_skas(int type, const void * addr,
return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
}
-static inline unsigned long maybe_map(unsigned long virt, int is_write)
-{
- pte_t pte;
-
- void *phys = um_virt_to_phys(current, virt, &pte);
- int dummy_code;
-
- if(IS_ERR(phys) || (is_write && !pte_write(pte))){
- if(handle_page_fault(virt, 0, is_write, 0, &dummy_code))
- return(0);
- phys = um_virt_to_phys(current, virt, NULL);
- }
- return((unsigned long) __va((unsigned long) phys));
-}
-
-static inline int buffer_op(unsigned long addr, int len,
- int (*op)(unsigned long addr, int len, void *arg),
- void *arg)
-{
- int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
- int remain = len, n;
-
- n = (*op)(addr, size, arg);
- if(n != 0)
- return(n < 0 ? remain : 0);
-
- addr += size;
- remain -= size;
- if(remain == 0)
- return(0);
-
- while(addr < ((addr + remain) & PAGE_MASK)){
- n = (*op)(addr, PAGE_SIZE, arg);
- if(n != 0)
- return(n < 0 ? remain : 0);
-
- addr += PAGE_SIZE;
- remain -= PAGE_SIZE;
- }
- if(remain == 0)
- return(0);
-
- n = (*op)(addr, remain, arg);
- if(n != 0)
- return(n < 0 ? remain : 0);
- return(0);
-}
-
-static inline int copy_chunk_from_user(unsigned long from, int len, void *arg)
-{
- unsigned long *to_ptr = arg, to = *to_ptr;
-
- from = maybe_map(from, 0);
- if(from == 0)
- return(-1);
-
- memcpy((void *) to, (void *) from, len);
- *to_ptr += len;
- return(0);
-}
-
-static inline int copy_from_user_skas(void *to, const void *from, int n)
-{
- if(segment_eq(get_fs(), KERNEL_DS)){
- memcpy(to, from, n);
- return(0);
- }
-
- return(access_ok_skas(VERIFY_READ, from, n) ?
- buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) :
- n);
-}
-
-static inline int copy_chunk_to_user(unsigned long to, int len, void *arg)
-{
- unsigned long *from_ptr = arg, from = *from_ptr;
-
- to = maybe_map(to, 1);
- if(to == 0)
- return(-1);
-
- memcpy((void *) to, (void *) from, len);
- *from_ptr += len;
- return(0);
-}
-
-static inline int copy_to_user_skas(void *to, const void *from, int n)
-{
- if(segment_eq(get_fs(), KERNEL_DS)){
- memcpy(to, from, n);
- return(0);
- }
-
- return(access_ok_skas(VERIFY_WRITE, to, n) ?
- buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) :
- n);
-}
-
-static inline int strncpy_chunk_from_user(unsigned long from, int len,
- void *arg)
-{
- char **to_ptr = arg, *to = *to_ptr;
- int n;
-
- from = maybe_map(from, 0);
- if(from == 0)
- return(-1);
-
- strncpy(to, (void *) from, len);
- n = strnlen(to, len);
- *to_ptr += n;
-
- if(n < len)
- return(1);
- return(0);
-}
-
-static inline int strncpy_from_user_skas(char *dst, const char *src, int count)
-{
- int n;
- char *ptr = dst;
-
- if(segment_eq(get_fs(), KERNEL_DS)){
- strncpy(dst, src, count);
- return(strnlen(dst, count));
- }
-
- if(!access_ok_skas(VERIFY_READ, src, 1))
- return(-EFAULT);
-
- n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user,
- &ptr);
- if(n != 0)
- return(-EFAULT);
- return(strnlen(dst, count));
-}
-
-static inline int clear_chunk(unsigned long addr, int len, void *unused)
-{
- addr = maybe_map(addr, 1);
- if(addr == 0)
- return(-1);
-
- memset((void *) addr, 0, len);
- return(0);
-}
-
-static inline int __clear_user_skas(void *mem, int len)
-{
- return(buffer_op((unsigned long) mem, len, clear_chunk, NULL));
-}
-
-static inline int clear_user_skas(void *mem, int len)
-{
- if(segment_eq(get_fs(), KERNEL_DS)){
- memset(mem, 0, len);
- return(0);
- }
-
- return(access_ok_skas(VERIFY_WRITE, mem, len) ?
- buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len);
-}
-
-static inline int strnlen_chunk(unsigned long str, int len, void *arg)
-{
- int *len_ptr = arg, n;
-
- str = maybe_map(str, 0);
- if(str == 0)
- return(-1);
-
- n = strnlen((void *) str, len);
- *len_ptr += n;
-
- if(n < len)
- return(1);
- return(0);
-}
-
-static inline int strnlen_user_skas(const void *str, int len)
-{
- int count = 0, n;
-
- if(segment_eq(get_fs(), KERNEL_DS))
- return(strnlen(str, len) + 1);
-
- n = buffer_op((unsigned long) str, len, strnlen_chunk, &count);
- if(n == 0)
- return(count + 1);
- return(-EFAULT);
-}
+extern int copy_from_user_skas(void *to, const void *from, int n);
+extern int copy_to_user_skas(void *to, const void *from, int n);
+extern int strncpy_from_user_skas(char *dst, const char *src, int count);
+extern int __clear_user_skas(void *mem, int len);
+extern int clear_user_skas(void *mem, int len);
+extern int strnlen_user_skas(const void *str, int len);
#endif
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index d163090c004c8..cfcfa0d60dfbd 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -7,6 +7,7 @@
#include <sys/mman.h>
#include <sys/ptrace.h>
#include "mem_user.h"
+#include "mem.h"
#include "user.h"
#include "os.h"
#include "proc_mm.h"
@@ -15,12 +16,12 @@ void map(int fd, unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x)
{
struct proc_mm_op map;
- struct mem_region *region;
- int prot, n;
+ __u64 offset;
+ int prot, n, phys_fd;
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
- region = phys_region(phys);
+ phys_fd = phys_mapping(phys, &offset);
map = ((struct proc_mm_op) { .op = MM_MMAP,
.u =
@@ -30,12 +31,12 @@ void map(int fd, unsigned long virt, unsigned long phys, unsigned long len,
.prot = prot,
.flags = MAP_SHARED |
MAP_FIXED,
- .fd = region->fd,
- .offset = phys_offset(phys)
+ .fd = phys_fd,
+ .offset = offset
} } } );
n = os_write_file(fd, &map, sizeof(map));
if(n != sizeof(map))
- printk("map : /proc/mm map failed, errno = %d\n", errno);
+ printk("map : /proc/mm map failed, err = %d\n", -n);
}
int unmap(int fd, void *addr, int len)
@@ -49,8 +50,13 @@ int unmap(int fd, void *addr, int len)
{ .addr = (unsigned long) addr,
.len = len } } } );
n = os_write_file(fd, &unmap, sizeof(unmap));
- if((n != 0) && (n != sizeof(unmap)))
- return(-errno);
+ if(n != sizeof(unmap)) {
+ if(n < 0)
+ return(n);
+ else if(n > 0)
+ return(-EIO);
+ }
+
return(0);
}
@@ -71,11 +77,15 @@ int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
.prot = prot } } } );
n = os_write_file(fd, &protect, sizeof(protect));
- if((n != 0) && (n != sizeof(protect))){
+ if(n != sizeof(protect)) {
+ if(n == 0) return(0);
+
if(must_succeed)
- panic("protect failed, errno = %d", errno);
- return(-errno);
+ panic("protect failed, err = %d", -n);
+
+ return(-EIO);
}
+
return(0);
}
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 5911cdd0c0b79..6cb9a6d028a90 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -22,9 +22,11 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
else from = -1;
mm->context.skas.mm_fd = new_mm(from);
- if(mm->context.skas.mm_fd < 0)
- panic("init_new_context_skas - new_mm failed, errno = %d\n",
- mm->context.skas.mm_fd);
+ if(mm->context.skas.mm_fd < 0){
+ printk("init_new_context_skas - new_mm failed, errno = %d\n",
+ mm->context.skas.mm_fd);
+ return(mm->context.skas.mm_fd);
+ }
return(0);
}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index cb91f8cd11390..be972aeea7fae 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -4,6 +4,7 @@
*/
#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
@@ -24,6 +25,19 @@
#include "os.h"
#include "proc_mm.h"
#include "skas_ptrace.h"
+#include "chan_user.h"
+#include "signal_user.h"
+
+int is_skas_winch(int pid, int fd, void *data)
+{
+ if(pid != getpid())
+ return(0);
+
+ register_winch_irq(-1, fd, -1, data);
+ return(1);
+}
+
+/* These are set once at boot time and not changed thereafter */
unsigned long exec_regs[FRAME_SIZE];
unsigned long exec_fp_regs[HOST_FP_SIZE];
@@ -43,37 +57,39 @@ static void handle_segv(int pid)
segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
}
-static void handle_trap(int pid, union uml_pt_regs *regs)
+/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
+static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu)
{
int err, syscall_nr, status;
syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
+ UPT_SYSCALL_NR(regs) = syscall_nr;
if(syscall_nr < 1){
relay_signal(SIGTRAP, regs);
return;
}
- UPT_SYSCALL_NR(regs) = syscall_nr;
- err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
- if(err < 0)
- panic("handle_trap - nullifying syscall failed errno = %d\n",
- errno);
+ if (!local_using_sysemu)
+ {
+ err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+ if(err < 0)
+ panic("handle_trap - nullifying syscall failed errno = %d\n",
+ errno);
- err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
- if(err < 0)
- panic("handle_trap - continuing to end of syscall failed, "
- "errno = %d\n", errno);
+ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+ if(err < 0)
+ panic("handle_trap - continuing to end of syscall failed, "
+ "errno = %d\n", errno);
- err = waitpid(pid, &status, WUNTRACED);
- if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
- panic("handle_trap - failed to wait at end of syscall, "
- "errno = %d, status = %d\n", errno, status);
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+ if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+ panic("handle_trap - failed to wait at end of syscall, "
+ "errno = %d, status = %d\n", errno, status);
+ }
handle_syscall(regs);
}
-int userspace_pid;
-
static int userspace_tramp(void *arg)
{
init_new_thread_signals(0);
@@ -83,7 +99,11 @@ static int userspace_tramp(void *arg)
return(0);
}
-void start_userspace(void)
+/* Each element set once, and only accessed by a single processor anyway */
+#define NR_CPUS 1
+int userspace_pid[NR_CPUS];
+
+void start_userspace(int cpu)
{
void *stack;
unsigned long sp;
@@ -101,7 +121,7 @@ void start_userspace(void)
panic("start_userspace : clone failed, errno = %d", errno);
do {
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("start_userspace : wait failed, errno = %d",
errno);
@@ -114,21 +134,27 @@ void start_userspace(void)
if(munmap(stack, PAGE_SIZE) < 0)
panic("start_userspace : munmap failed, errno = %d\n", errno);
- userspace_pid = pid;
+ userspace_pid[cpu] = pid;
}
void userspace(union uml_pt_regs *regs)
{
- int err, status, op;
+ int err, status, op, pid = userspace_pid[0];
+ int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
restore_registers(regs);
- err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0);
+ local_using_sysemu = get_using_sysemu();
+
+ if (local_using_sysemu)
+ err = ptrace(PTRACE_SYSEMU, pid, 0, 0);
+ else
+ err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
if(err)
- panic("userspace - PTRACE_SYSCALL failed, errno = %d\n",
- errno);
+ panic("userspace - PTRACE_%s failed, errno = %d\n",
+ local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
while(1){
- err = waitpid(userspace_pid, &status, WUNTRACED);
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
if(err < 0)
panic("userspace - waitpid failed, errno = %d\n",
errno);
@@ -139,16 +165,17 @@ void userspace(union uml_pt_regs *regs)
if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){
case SIGSEGV:
- handle_segv(userspace_pid);
+ handle_segv(pid);
break;
case SIGTRAP:
- handle_trap(userspace_pid, regs);
+ handle_trap(pid, regs, local_using_sysemu);
break;
case SIGIO:
case SIGVTALRM:
case SIGILL:
case SIGBUS:
case SIGFPE:
+ case SIGWINCH:
user_signal(WSTOPSIG(status), regs);
break;
default:
@@ -160,25 +187,46 @@ void userspace(union uml_pt_regs *regs)
restore_registers(regs);
- op = singlestepping_skas() ? PTRACE_SINGLESTEP :
- PTRACE_SYSCALL;
- err = ptrace(op, userspace_pid, 0, 0);
+ /*Now we ended the syscall, so re-read local_using_sysemu.*/
+ local_using_sysemu = get_using_sysemu();
+
+ if (local_using_sysemu)
+ op = singlestepping_skas() ? PTRACE_SINGLESTEP :
+ PTRACE_SYSEMU;
+ else
+ op = singlestepping_skas() ? PTRACE_SINGLESTEP :
+ PTRACE_SYSCALL;
+
+ err = ptrace(op, pid, 0, 0);
if(err)
- panic("userspace - PTRACE_SYSCALL failed, "
- "errno = %d\n", errno);
+ panic("userspace - PTRACE_%s failed, "
+ "errno = %d\n",
+ local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
}
}
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int))
{
+ unsigned long flags;
jmp_buf switch_buf, fork_buf;
*switch_buf_ptr = &switch_buf;
*fork_buf_ptr = &fork_buf;
- if(setjmp(fork_buf) == 0)
+ /* Somewhat subtle - siglongjmp restores the signal mask before doing
+ * the longjmp. This means that when jumping from one stack to another
+ * when the target stack has interrupts enabled, an interrupt may occur
+ * on the source stack. This is bad when starting up a process because
+ * it's not supposed to get timer ticks until it has been scheduled.
+ * So, we disable interrupts around the sigsetjmp to ensure that
+ * they can't happen until we get back here where they are safe.
+ */
+ flags = get_signals();
+ block_signals();
+ if(sigsetjmp(fork_buf, 1) == 0)
new_thread_proc(stack, handler);
+ set_signals(flags);
remove_sigstack();
}
@@ -189,16 +237,16 @@ void thread_wait(void *sw, void *fb)
*switch_buf = &buf;
fork_buf = fb;
- if(setjmp(buf) == 0)
- longjmp(*fork_buf, 1);
+ if(sigsetjmp(buf, 1) == 0)
+ siglongjmp(*fork_buf, 1);
}
-static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs,
- unsigned long *fp_regs)
+static int move_registers(int pid, int int_op, int fp_op,
+ union uml_pt_regs *regs, unsigned long *fp_regs)
{
- if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0)
+ if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
return(-errno);
- if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0)
+ if(ptrace(fp_op, pid, 0, fp_regs) < 0)
return(-errno);
return(0);
}
@@ -217,10 +265,11 @@ void save_registers(union uml_pt_regs *regs)
fp_regs = regs->skas.fp;
}
- err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs);
+ err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs,
+ fp_regs);
if(err)
panic("save_registers - saving registers failed, errno = %d\n",
- err);
+ -err);
}
void restore_registers(union uml_pt_regs *regs)
@@ -237,10 +286,11 @@ void restore_registers(union uml_pt_regs *regs)
fp_regs = regs->skas.fp;
}
- err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs);
+ err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs,
+ fp_regs);
if(err)
panic("restore_registers - saving registers failed, "
- "errno = %d\n", err);
+ "errno = %d\n", -err);
}
void switch_threads(void *me, void *next)
@@ -248,8 +298,8 @@ void switch_threads(void *me, void *next)
jmp_buf my_buf, **me_ptr = me, *next_buf = next;
*me_ptr = &my_buf;
- if(setjmp(my_buf) == 0)
- longjmp(*next_buf, 1);
+ if(sigsetjmp(my_buf, 1) == 0)
+ siglongjmp(*next_buf, 1);
}
static jmp_buf initial_jmpbuf;
@@ -265,14 +315,14 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
int n;
*fork_buf_ptr = &initial_jmpbuf;
- n = setjmp(initial_jmpbuf);
+ n = sigsetjmp(initial_jmpbuf, 1);
if(n == 0)
new_thread_proc((void *) stack, new_thread_handler);
else if(n == 1)
remove_sigstack();
else if(n == 2){
(*cb_proc)(cb_arg);
- longjmp(*cb_back, 1);
+ siglongjmp(*cb_back, 1);
}
else if(n == 3){
kmalloc_ok = 0;
@@ -282,7 +332,7 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
kmalloc_ok = 0;
return(1);
}
- longjmp(**switch_buf, 1);
+ siglongjmp(**switch_buf, 1);
}
void remove_sigstack(void)
@@ -304,8 +354,8 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
cb_back = &here;
block_signals();
- if(setjmp(here) == 0)
- longjmp(initial_jmpbuf, 2);
+ if(sigsetjmp(here, 1) == 0)
+ siglongjmp(initial_jmpbuf, 2);
unblock_signals();
cb_proc = NULL;
@@ -316,22 +366,23 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
void halt_skas(void)
{
block_signals();
- longjmp(initial_jmpbuf, 3);
+ siglongjmp(initial_jmpbuf, 3);
}
void reboot_skas(void)
{
block_signals();
- longjmp(initial_jmpbuf, 4);
+ siglongjmp(initial_jmpbuf, 4);
}
int new_mm(int from)
{
struct proc_mm_op copy;
- int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0);
+ int n, fd = os_open_file("/proc/mm",
+ of_cloexec(of_write(OPENFLAGS())), 0);
if(fd < 0)
- return(-errno);
+ return(fd);
if(from != -1){
copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
@@ -340,8 +391,9 @@ int new_mm(int from)
n = os_write_file(fd, &copy, sizeof(copy));
if(n != sizeof(copy))
printk("new_mm : /proc/mm copy_segments failed, "
- "errno = %d\n", errno);
+ "err = %d\n", -n);
}
+
return(fd);
}
@@ -349,7 +401,8 @@ void switch_mm_skas(int mm_fd)
{
int err;
- err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd);
+#warning need cpu pid in switch_mm_skas
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
if(err)
panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
errno);
@@ -357,7 +410,8 @@ void switch_mm_skas(int mm_fd)
void kill_off_processes_skas(void)
{
- os_kill_process(userspace_pid, 1);
+#warning need to loop over userspace_pids in kill_off_processes_skas
+ os_kill_process(userspace_pid[0], 1);
}
void init_registers(int pid)
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 128146c80dfa5..538bd0feabb44 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -6,6 +6,12 @@
#include "linux/sched.h"
#include "linux/slab.h"
#include "linux/ptrace.h"
+#include "linux/proc_fs.h"
+#include "linux/file.h"
+#include "linux/errno.h"
+#include "linux/init.h"
+#include "asm/uaccess.h"
+#include "asm/atomic.h"
#include "kern_util.h"
#include "time_user.h"
#include "signal_user.h"
@@ -17,6 +23,61 @@
#include "kern.h"
#include "mode.h"
+static atomic_t using_sysemu;
+int sysemu_supported;
+
+void set_using_sysemu(int value)
+{
+ atomic_set(&using_sysemu, sysemu_supported && value);
+}
+
+int get_using_sysemu(void)
+{
+ return atomic_read(&using_sysemu);
+}
+
+int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
+{
+ if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/
+ *eof = 1;
+
+ return strlen(buf);
+}
+
+int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data)
+{
+ char tmp[2];
+
+ if (copy_from_user(tmp, buf, 1))
+ return -EFAULT;
+
+ if (tmp[0] == '0' || tmp[0] == '1')
+ set_using_sysemu(tmp[0] - '0');
+ return count; /*We use the first char, but pretend to write everything*/
+}
+
+int __init make_proc_sysemu(void)
+{
+ struct proc_dir_entry *ent;
+ if (mode_tt || !sysemu_supported)
+ return 0;
+
+ ent = create_proc_entry("sysemu", 0600, &proc_root);
+
+ if (ent == NULL)
+ {
+ printk("Failed to register /proc/sysemu\n");
+ return(0);
+ }
+
+ ent->read_proc = proc_read_sysemu;
+ ent->write_proc = proc_write_sysemu;
+
+ return 0;
+}
+
+late_initcall(make_proc_sysemu);
+
int singlestepping_skas(void)
{
int ret = current->ptrace & PT_DTRACE;
@@ -61,11 +122,13 @@ void new_thread_handler(int sig)
thread_wait(&current->thread.mode.skas.switch_buf,
current->thread.mode.skas.fork_buf);
-#ifdef CONFIG_SMP
- schedule_tail(NULL);
-#endif
+ if(current->thread.prev_sched != NULL)
+ schedule_tail(current->thread.prev_sched);
current->thread.prev_sched = NULL;
+ /* The return value is 1 if the kernel thread execs a process,
+ * 0 if it just exits
+ */
n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
if(n == 1)
userspace(&current->thread.regs.regs);
@@ -93,11 +156,11 @@ void fork_handler(int sig)
current->thread.mode.skas.fork_buf);
force_flush_all();
-#ifdef CONFIG_SMP
+ if(current->thread.prev_sched == NULL)
+ panic("blech");
+
schedule_tail(current->thread.prev_sched);
-#endif
current->thread.prev_sched = NULL;
- unblock_signals();
userspace(&current->thread.regs.regs);
}
@@ -136,7 +199,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
void init_idle_skas(void)
{
- cpu_tasks[current->thread_info->cpu].pid = os_getpid();
+ cpu_tasks[current_thread->cpu].pid = os_getpid();
default_idle();
}
@@ -160,11 +223,11 @@ static int start_kernel_proc(void *unused)
int start_uml_skas(void)
{
- start_userspace();
+ start_userspace(0);
capture_signal_stack();
+ uml_idle_timer();
init_new_thread_signals(1);
- idle_timer();
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
@@ -175,12 +238,14 @@ int start_uml_skas(void)
int external_pid_skas(struct task_struct *task)
{
- return(userspace_pid);
+#warning Need to look up userspace_pid by cpu
+ return(userspace_pid[0]);
}
int thread_pid_skas(struct task_struct *task)
{
- return(userspace_pid);
+#warning Need to look up userspace_pid by cpu
+ return(userspace_pid[0]);
}
/*
diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile
index 2ad8271c604d5..3eeea057c591d 100644
--- a/arch/um/kernel/skas/sys-i386/Makefile
+++ b/arch/um/kernel/skas/sys-i386/Makefile
@@ -10,5 +10,3 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-clean :
diff --git a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c
index 5f340e102b169..b015d1960576e 100644
--- a/arch/um/kernel/skas/sys-i386/sigcontext.c
+++ b/arch/um/kernel/skas/sys-i386/sigcontext.c
@@ -12,10 +12,9 @@
#include "kern_util.h"
#include "user.h"
#include "sigcontext.h"
+#include "mode.h"
-extern int userspace_pid;
-
-int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr)
+int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr)
{
struct sigcontext sc, *from = from_ptr;
unsigned long fpregs[FP_FRAME_SIZE];
@@ -41,13 +40,12 @@ int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr)
regs->skas.regs[EIP] = sc.eip;
regs->skas.regs[CS] = sc.cs;
regs->skas.regs[EFL] = sc.eflags;
- regs->skas.regs[UESP] = sc.esp_at_signal;
regs->skas.regs[SS] = sc.ss;
regs->skas.fault_addr = sc.cr2;
regs->skas.fault_type = FAULT_WRITE(sc.err);
regs->skas.trap_type = sc.trapno;
- err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs);
+ err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs);
if(err < 0){
printk("copy_sc_to_user - PTRACE_SETFPREGS failed, "
"errno = %d\n", errno);
@@ -57,8 +55,9 @@ int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr)
return(0);
}
-int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs,
- unsigned long fault_addr, int fault_type)
+int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp,
+ union uml_pt_regs *regs, unsigned long fault_addr,
+ int fault_type)
{
struct sigcontext sc, *to = to_ptr;
struct _fpstate *to_fp;
@@ -86,7 +85,7 @@ int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs,
sc.err = TO_SC_ERR(fault_type);
sc.trapno = regs->skas.trap_type;
- err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs);
+ err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs);
if(err < 0){
printk("copy_sc_to_user - PTRACE_GETFPREGS failed, "
"errno = %d\n", errno);
diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
index bc837a77e61f9..1d7eca5a8d9a0 100644
--- a/arch/um/kernel/skas/syscall_kern.c
+++ b/arch/um/kernel/skas/syscall_kern.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
index caccb772bfdb4..34fd5f94e2f4a 100644
--- a/arch/um/kernel/skas/syscall_user.c
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -22,7 +22,7 @@ void handle_syscall(union uml_pt_regs *regs)
index = record_syscall_start(UPT_SYSCALL_NR(regs));
- syscall_trace();
+ syscall_trace(regs, 1);
result = execute_syscall(regs);
REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
@@ -30,7 +30,7 @@ void handle_syscall(union uml_pt_regs *regs)
(result == -ERESTARTNOINTR))
do_signal(result);
- syscall_trace();
+ syscall_trace(regs, 0);
record_syscall_end(index, result);
}
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
index 0906f65b89235..2c47e78c1ebc6 100644
--- a/arch/um/kernel/skas/trap_user.c
+++ b/arch/um/kernel/skas/trap_user.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -35,14 +35,10 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
errno = save_errno;
}
-extern int missed_ticks[];
-
void user_signal(int sig, union uml_pt_regs *regs)
{
struct signal_info *info;
- if(sig == SIGVTALRM)
- missed_ticks[cpu()]++;
regs->skas.is_user = 1;
regs->skas.fault_addr = 0;
regs->skas.fault_type = 0;
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
new file mode 100644
index 0000000000000..7fa723278620b
--- /dev/null
+++ b/arch/um/kernel/skas/uaccess.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/string.h"
+#include "linux/fs.h"
+#include "linux/highmem.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/uaccess.h"
+#include "kern_util.h"
+
+extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
+ pte_t *pte_out);
+
+static unsigned long maybe_map(unsigned long virt, int is_write)
+{
+ pte_t pte;
+ int err;
+
+ void *phys = um_virt_to_phys(current, virt, &pte);
+ int dummy_code;
+
+ if(IS_ERR(phys) || (is_write && !pte_write(pte))){
+ err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
+ if(err)
+ return(0);
+ phys = um_virt_to_phys(current, virt, NULL);
+ }
+ return((unsigned long) phys);
+}
+
+static int do_op(unsigned long addr, int len, int is_write,
+ int (*op)(unsigned long addr, int len, void *arg), void *arg)
+{
+ struct page *page;
+ int n;
+
+ addr = maybe_map(addr, is_write);
+ if(addr == -1)
+ return(-1);
+
+ page = phys_to_page(addr);
+ addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
+ n = (*op)(addr, len, arg);
+ kunmap(page);
+
+ return(n);
+}
+
+static int buffer_op(unsigned long addr, int len, int is_write,
+ int (*op)(unsigned long addr, int len, void *arg),
+ void *arg)
+{
+ int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
+ int remain = len, n;
+
+ n = do_op(addr, size, is_write, op, arg);
+ if(n != 0)
+ return(n < 0 ? remain : 0);
+
+ addr += size;
+ remain -= size;
+ if(remain == 0)
+ return(0);
+
+ while(addr < ((addr + remain) & PAGE_MASK)){
+ n = do_op(addr, PAGE_SIZE, is_write, op, arg);
+ if(n != 0)
+ return(n < 0 ? remain : 0);
+
+ addr += PAGE_SIZE;
+ remain -= PAGE_SIZE;
+ }
+ if(remain == 0)
+ return(0);
+
+ n = do_op(addr, remain, is_write, op, arg);
+ if(n != 0)
+ return(n < 0 ? remain : 0);
+ return(0);
+}
+
+static int copy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+ unsigned long *to_ptr = arg, to = *to_ptr;
+
+ memcpy((void *) to, (void *) from, len);
+ *to_ptr += len;
+ return(0);
+}
+
+int copy_from_user_skas(void *to, const void *from, int n)
+{
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ memcpy(to, from, n);
+ return(0);
+ }
+
+ return(access_ok_skas(VERIFY_READ, from, n) ?
+ buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
+ n);
+}
+
+static int copy_chunk_to_user(unsigned long to, int len, void *arg)
+{
+ unsigned long *from_ptr = arg, from = *from_ptr;
+
+ memcpy((void *) to, (void *) from, len);
+ *from_ptr += len;
+ return(0);
+}
+
+int copy_to_user_skas(void *to, const void *from, int n)
+{
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ memcpy(to, from, n);
+ return(0);
+ }
+
+ return(access_ok_skas(VERIFY_WRITE, to, n) ?
+ buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
+ n);
+}
+
+static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
+{
+ char **to_ptr = arg, *to = *to_ptr;
+ int n;
+
+ strncpy(to, (void *) from, len);
+ n = strnlen(to, len);
+ *to_ptr += n;
+
+ if(n < len)
+ return(1);
+ return(0);
+}
+
+int strncpy_from_user_skas(char *dst, const char *src, int count)
+{
+ int n;
+ char *ptr = dst;
+
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ strncpy(dst, src, count);
+ return(strnlen(dst, count));
+ }
+
+ if(!access_ok_skas(VERIFY_READ, src, 1))
+ return(-EFAULT);
+
+ n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
+ &ptr);
+ if(n != 0)
+ return(-EFAULT);
+ return(strnlen(dst, count));
+}
+
+static int clear_chunk(unsigned long addr, int len, void *unused)
+{
+ memset((void *) addr, 0, len);
+ return(0);
+}
+
+int __clear_user_skas(void *mem, int len)
+{
+ return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
+}
+
+int clear_user_skas(void *mem, int len)
+{
+ if(segment_eq(get_fs(), KERNEL_DS)){
+ memset(mem, 0, len);
+ return(0);
+ }
+
+ return(access_ok_skas(VERIFY_WRITE, mem, len) ?
+ buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
+}
+
+static int strnlen_chunk(unsigned long str, int len, void *arg)
+{
+ int *len_ptr = arg, n;
+
+ n = strnlen((void *) str, len);
+ *len_ptr += n;
+
+ if(n < len)
+ return(1);
+ return(0);
+}
+
+int strnlen_user_skas(const void *str, int len)
+{
+ int count = 0, n;
+
+ if(segment_eq(get_fs(), KERNEL_DS))
+ return(strnlen(str, len) + 1);
+
+ n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
+ if(n == 0)
+ return(count + 1);
+ return(-EFAULT);
+}
+
+/*
+ * 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/util/Makefile b/arch/um/kernel/skas/util/Makefile
index e62dc253e8954..08e95a65ea190 100644
--- a/arch/um/kernel/skas/util/Makefile
+++ b/arch/um/kernel/skas/util/Makefile
@@ -1,10 +1,9 @@
all: mk_ptregs
mk_ptregs : mk_ptregs.o
- $(CC) -o mk_ptregs mk_ptregs.o
+ $(HOSTCC) -o mk_ptregs mk_ptregs.o
mk_ptregs.o : mk_ptregs.c
- $(CC) -c $<
+ $(HOSTCC) -c $<
-clean :
- $(RM) -f mk_ptregs *.o *~
+clean-files := mk_ptregs *.o *~
diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c
index 6587910173732..116f74d2c334f 100644
--- a/arch/um/kernel/skas/util/mk_ptregs.c
+++ b/arch/um/kernel/skas/util/mk_ptregs.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
#include <asm/ptrace.h>
#include <asm/user.h>
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index b8158556c4a57..8e970e0f06083 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -1,9 +1,15 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
#include "linux/config.h"
+#include "linux/percpu.h"
+#include "asm/pgalloc.h"
+#include "asm/tlb.h"
+
+/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
#ifdef CONFIG_SMP
@@ -23,7 +29,7 @@
#include "os.h"
/* CPU online map, set by smp_boot_cpus */
-unsigned long cpu_online_map = cpumask_of_cpu(0);
+unsigned long cpu_online_map = CPU_MASK_NONE;
EXPORT_SYMBOL(cpu_online_map);
@@ -33,14 +39,6 @@ EXPORT_SYMBOL(cpu_online_map);
*/
struct cpuinfo_um cpu_data[NR_CPUS];
-spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED;
-
-atomic_t global_bh_count;
-
-/* Not used by UML */
-unsigned char global_irq_holder = NO_PROC_ID;
-unsigned volatile long global_irq_lock;
-
/* Set when the idlers are all forked */
int smp_threads_ready = 0;
@@ -55,80 +53,44 @@ struct task_struct *idle_threads[NR_CPUS];
void smp_send_reschedule(int cpu)
{
- write(cpu_data[cpu].ipi_pipe[1], "R", 1);
+ os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
num_reschedules_sent++;
}
-static void show(char * str)
-{
- int cpu = smp_processor_id();
-
- printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu);
-}
-
-#define MAXCOUNT 100000000
-
-static inline void wait_on_bh(void)
-{
- int count = MAXCOUNT;
- do {
- if (!--count) {
- show("wait_on_bh");
- count = ~0;
- }
- /* nothing .. wait for the other bh's to go away */
- } while (atomic_read(&global_bh_count) != 0);
-}
-
-/*
- * This is called when we want to synchronize with
- * bottom half handlers. We need to wait until
- * no other CPU is executing any bottom half handler.
- *
- * Don't wait if we're already running in an interrupt
- * context or are inside a bh handler.
- */
-void synchronize_bh(void)
-{
- if (atomic_read(&global_bh_count) && !in_interrupt())
- wait_on_bh();
-}
-
void smp_send_stop(void)
{
int i;
printk(KERN_INFO "Stopping all CPUs...");
for(i = 0; i < num_online_cpus(); i++){
- if(i == current->thread_info->cpu)
+ if(i == current_thread->cpu)
continue;
- write(cpu_data[i].ipi_pipe[1], "S", 1);
+ os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
}
printk("done\n");
}
-static cpumask_t smp_commenced_mask;
-static cpumask_t smp_callin_map = CPU_MASK_NONE;
+static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
+static cpumask_t cpu_callin_map = CPU_MASK_NONE;
static int idle_proc(void *cpup)
{
int cpu = (int) cpup, err;
err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
- if(err)
- panic("CPU#%d failed to create IPI pipe, errno = %d", cpu,
- -err);
+ if(err < 0)
+ panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
activate_ipi(cpu_data[cpu].ipi_pipe[0],
current->thread.mode.tt.extern_pid);
wmb();
- if (cpu_test_and_set(cpu, &smp_callin_map)) {
+ if (cpu_test_and_set(cpu, cpu_callin_map)) {
printk("huh, CPU#%d already present??\n", cpu);
BUG();
}
- while (!cpu_isset(cpu, &smp_commenced_mask))
+ while (!cpu_isset(cpu, smp_commenced_mask))
cpu_relax();
cpu_set(cpu, cpu_online_map);
@@ -143,14 +105,16 @@ static struct task_struct *idle_thread(int cpu)
current->thread.request.u.thread.proc = idle_proc;
current->thread.request.u.thread.arg = (void *) cpu;
- new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL);
- if(IS_ERR(new_task)) panic("do_fork failed in idle_thread");
+ new_task = fork_idle(cpu);
+ if(IS_ERR(new_task))
+ panic("copy_process failed in idle_thread, error = %ld",
+ PTR_ERR(new_task));
cpu_tasks[cpu] = ((struct cpu_task)
{ .pid = new_task->thread.mode.tt.extern_pid,
.task = new_task } );
idle_threads[cpu] = new_task;
- CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c,
+ CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
sizeof(c)),
({ panic("skas mode doesn't support SMP"); }));
return(new_task);
@@ -160,15 +124,17 @@ void smp_prepare_cpus(unsigned int maxcpus)
{
struct task_struct *idle;
unsigned long waittime;
- int err, cpu;
+ int err, cpu, me = smp_processor_id();
- cpu_set(0, cpu_online_map);
- cpu_set(0, smp_callin_map);
+ cpu_clear(me, cpu_online_map);
+ cpu_set(me, cpu_online_map);
+ cpu_set(me, cpu_callin_map);
- err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
- if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
+ err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
+ if(err < 0)
+ panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
- activate_ipi(cpu_data[0].ipi_pipe[0],
+ activate_ipi(cpu_data[me].ipi_pipe[0],
current->thread.mode.tt.extern_pid);
for(cpu = 1; cpu < ncpus; cpu++){
@@ -180,10 +146,10 @@ void smp_prepare_cpus(unsigned int maxcpus)
unhash_process(idle);
waittime = 200000000;
- while (waittime-- && !cpu_isset(cpu, smp_callin_map))
+ while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
cpu_relax();
- if (cpu_isset(cpu, smp_callin_map))
+ if (cpu_isset(cpu, cpu_callin_map))
printk("done\n");
else printk("failed\n");
}
@@ -216,7 +182,7 @@ void IPI_handler(int cpu)
int fd;
fd = cpu_data[cpu].ipi_pipe[0];
- while (read(fd, &c, 1) == 1) {
+ while (os_read_file(fd, &c, 1) == 1) {
switch (c) {
case 'C':
smp_call_function_slave(cpu);
@@ -276,9 +242,9 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
info = _info;
for (i=0;i<NR_CPUS;i++)
- if((i != current->thread_info->cpu) &&
+ if((i != current_thread->cpu) &&
cpu_isset(i, cpu_online_map))
- write(cpu_data[i].ipi_pipe[1], "C", 1);
+ os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
while (atomic_read(&scf_started) != cpus)
barrier();
diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
index 77a7d922e9917..6a385c075c7e0 100644
--- a/arch/um/kernel/sys_call_table.c
+++ b/arch/um/kernel/sys_call_table.c
@@ -5,7 +5,6 @@
#include "linux/config.h"
#include "linux/unistd.h"
-#include "linux/version.h"
#include "linux/sys.h"
#include "linux/swap.h"
#include "linux/syscalls.h"
@@ -14,251 +13,50 @@
#include "sysdep/syscalls.h"
#include "kern_util.h"
-extern syscall_handler_t sys_restart_syscall;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_exit;
+#ifdef CONFIG_NFSD
+#define NFSSERVCTL sys_nfsservctl
+#else
+#define NFSSERVCTL sys_ni_syscall
+#endif
+
+#define LAST_GENERIC_SYSCALL __NR_vserver
+
+#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+#define LAST_SYSCALL LAST_GENERIC_SYSCALL
+#else
+#define LAST_SYSCALL LAST_ARCH_SYSCALL
+#endif
+
extern syscall_handler_t sys_fork;
-extern syscall_handler_t sys_creat;
-extern syscall_handler_t sys_link;
-extern syscall_handler_t sys_unlink;
-extern syscall_handler_t sys_chdir;
-extern syscall_handler_t sys_mknod;
-extern syscall_handler_t sys_chmod;
-extern syscall_handler_t sys_lchown16;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_stat;
-extern syscall_handler_t sys_getpid;
-extern syscall_handler_t sys_oldumount;
-extern syscall_handler_t sys_setuid16;
-extern syscall_handler_t sys_getuid16;
+extern syscall_handler_t sys_execve;
+extern syscall_handler_t um_time;
+extern syscall_handler_t um_mount;
+extern syscall_handler_t um_stime;
extern syscall_handler_t sys_ptrace;
-extern syscall_handler_t sys_alarm;
-extern syscall_handler_t sys_fstat;
-extern syscall_handler_t sys_pause;
-extern syscall_handler_t sys_utime;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_access;
-extern syscall_handler_t sys_nice;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_sync;
-extern syscall_handler_t sys_kill;
-extern syscall_handler_t sys_rename;
-extern syscall_handler_t sys_mkdir;
-extern syscall_handler_t sys_rmdir;
extern syscall_handler_t sys_pipe;
-extern syscall_handler_t sys_times;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_brk;
-extern syscall_handler_t sys_setgid16;
-extern syscall_handler_t sys_getgid16;
-extern syscall_handler_t sys_signal;
-extern syscall_handler_t sys_geteuid16;
-extern syscall_handler_t sys_getegid16;
-extern syscall_handler_t sys_acct;
-extern syscall_handler_t sys_umount;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_ioctl;
-extern syscall_handler_t sys_fcntl;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_setpgid;
-extern syscall_handler_t sys_ni_syscall;
extern syscall_handler_t sys_olduname;
-extern syscall_handler_t sys_umask;
-extern syscall_handler_t sys_chroot;
-extern syscall_handler_t sys_ustat;
-extern syscall_handler_t sys_dup2;
-extern syscall_handler_t sys_getppid;
-extern syscall_handler_t sys_getpgrp;
extern syscall_handler_t sys_sigaction;
-extern syscall_handler_t sys_sgetmask;
-extern syscall_handler_t sys_ssetmask;
-extern syscall_handler_t sys_setreuid16;
-extern syscall_handler_t sys_setregid16;
extern syscall_handler_t sys_sigsuspend;
-extern syscall_handler_t sys_sigpending;
-extern syscall_handler_t sys_sethostname;
-extern syscall_handler_t sys_setrlimit;
-extern syscall_handler_t sys_old_getrlimit;
-extern syscall_handler_t sys_getrusage;
-extern syscall_handler_t sys_gettimeofday;
-extern syscall_handler_t sys_settimeofday;
-extern syscall_handler_t sys_getgroups16;
-extern syscall_handler_t sys_setgroups16;
-extern syscall_handler_t sys_symlink;
-extern syscall_handler_t sys_lstat;
-extern syscall_handler_t sys_readlink;
-extern syscall_handler_t sys_swapon;
-extern syscall_handler_t sys_uselib;
-extern syscall_handler_t sys_reboot;
extern syscall_handler_t old_readdir;
-extern syscall_handler_t sys_munmap;
-extern syscall_handler_t sys_truncate;
-extern syscall_handler_t sys_ftruncate;
-extern syscall_handler_t sys_fchmod;
-extern syscall_handler_t sys_fchown16;
-extern syscall_handler_t sys_getpriority;
-extern syscall_handler_t sys_setpriority;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_statfs;
-extern syscall_handler_t sys_fstatfs;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_socketcall;
-extern syscall_handler_t sys_syslog;
-extern syscall_handler_t sys_setitimer;
-extern syscall_handler_t sys_getitimer;
-extern syscall_handler_t sys_newstat;
-extern syscall_handler_t sys_newlstat;
-extern syscall_handler_t sys_newfstat;
extern syscall_handler_t sys_uname;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_vhangup;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_swapoff;
-extern syscall_handler_t sys_sysinfo;
extern syscall_handler_t sys_ipc;
-extern syscall_handler_t sys_fsync;
extern syscall_handler_t sys_sigreturn;
-extern syscall_handler_t sys_rt_sigreturn;
extern syscall_handler_t sys_clone;
-extern syscall_handler_t sys_setdomainname;
-extern syscall_handler_t sys_newuname;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_adjtimex;
-extern syscall_handler_t sys_mprotect;
-extern syscall_handler_t sys_sigprocmask;
-extern syscall_handler_t sys_init_module;
-extern syscall_handler_t sys_delete_module;
-extern syscall_handler_t sys_quotactl;
-extern syscall_handler_t sys_getpgid;
-extern syscall_handler_t sys_fchdir;
-extern syscall_handler_t sys_bdflush;
-extern syscall_handler_t sys_sysfs;
-extern syscall_handler_t sys_personality;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_setfsuid16;
-extern syscall_handler_t sys_setfsgid16;
-extern syscall_handler_t sys_llseek;
-extern syscall_handler_t sys_getdents;
-extern syscall_handler_t sys_flock;
-extern syscall_handler_t sys_msync;
-extern syscall_handler_t sys_readv;
-extern syscall_handler_t sys_writev;
-extern syscall_handler_t sys_getsid;
-extern syscall_handler_t sys_fdatasync;
-extern syscall_handler_t sys_mlock;
-extern syscall_handler_t sys_munlock;
-extern syscall_handler_t sys_mlockall;
-extern syscall_handler_t sys_munlockall;
-extern syscall_handler_t sys_sched_setparam;
-extern syscall_handler_t sys_sched_getparam;
-extern syscall_handler_t sys_sched_setscheduler;
-extern syscall_handler_t sys_sched_getscheduler;
-extern syscall_handler_t sys_sched_get_priority_max;
-extern syscall_handler_t sys_sched_get_priority_min;
-extern syscall_handler_t sys_sched_rr_get_interval;
-extern syscall_handler_t sys_nanosleep;
-extern syscall_handler_t sys_mremap;
-extern syscall_handler_t sys_setresuid16;
-extern syscall_handler_t sys_getresuid16;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_poll;
-extern syscall_handler_t sys_nfsservctl;
-extern syscall_handler_t sys_setresgid16;
-extern syscall_handler_t sys_getresgid16;
-extern syscall_handler_t sys_prctl;
-extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_rt_sigreturn;
extern syscall_handler_t sys_rt_sigaction;
-extern syscall_handler_t sys_rt_sigprocmask;
-extern syscall_handler_t sys_rt_sigpending;
-extern syscall_handler_t sys_rt_sigtimedwait;
-extern syscall_handler_t sys_rt_sigqueueinfo;
-extern syscall_handler_t sys_rt_sigsuspend;
-extern syscall_handler_t sys_pread64;
-extern syscall_handler_t sys_pwrite64;
-extern syscall_handler_t sys_chown16;
-extern syscall_handler_t sys_getcwd;
-extern syscall_handler_t sys_capget;
-extern syscall_handler_t sys_capset;
extern syscall_handler_t sys_sigaltstack;
-extern syscall_handler_t sys_sendfile;
-extern syscall_handler_t sys_ni_syscall;
-extern syscall_handler_t sys_ni_syscall;
extern syscall_handler_t sys_vfork;
-extern syscall_handler_t sys_getrlimit;
extern syscall_handler_t sys_mmap2;
-extern syscall_handler_t sys_truncate64;
-extern syscall_handler_t sys_ftruncate64;
-extern syscall_handler_t sys_stat64;
-extern syscall_handler_t sys_lstat64;
-extern syscall_handler_t sys_fstat64;
-extern syscall_handler_t sys_lchown;
-extern syscall_handler_t sys_getuid;
-extern syscall_handler_t sys_getgid;
-extern syscall_handler_t sys_geteuid;
-extern syscall_handler_t sys_getegid;
-extern syscall_handler_t sys_setreuid;
-extern syscall_handler_t sys_setregid;
-extern syscall_handler_t sys_getgroups;
-extern syscall_handler_t sys_setgroups;
-extern syscall_handler_t sys_fchown;
-extern syscall_handler_t sys_setresuid;
-extern syscall_handler_t sys_getresuid;
-extern syscall_handler_t sys_setresgid;
-extern syscall_handler_t sys_getresgid;
-extern syscall_handler_t sys_chown;
-extern syscall_handler_t sys_setuid;
-extern syscall_handler_t sys_setgid;
-extern syscall_handler_t sys_setfsuid;
-extern syscall_handler_t sys_setfsgid;
-extern syscall_handler_t sys_pivot_root;
-extern syscall_handler_t sys_mincore;
-extern syscall_handler_t sys_madvise;
-extern syscall_handler_t sys_fcntl64;
-extern syscall_handler_t sys_getdents64;
-extern syscall_handler_t sys_gettid;
-extern syscall_handler_t sys_readahead;
-extern syscall_handler_t sys_tkill;
-extern syscall_handler_t sys_sendfile64;
-extern syscall_handler_t sys_futex;
-extern syscall_handler_t sys_sched_setaffinity;
-extern syscall_handler_t sys_sched_getaffinity;
-extern syscall_handler_t sys_io_setup;
-extern syscall_handler_t sys_io_destroy;
-extern syscall_handler_t sys_io_getevents;
-extern syscall_handler_t sys_io_submit;
-extern syscall_handler_t sys_io_cancel;
-extern syscall_handler_t sys_exit_group;
-extern syscall_handler_t sys_lookup_dcookie;
-extern syscall_handler_t sys_epoll_create;
-extern syscall_handler_t sys_epoll_ctl;
-extern syscall_handler_t sys_epoll_wait;
-extern syscall_handler_t sys_remap_file_pages;
-extern syscall_handler_t sys_set_tid_address;
-
-#ifdef CONFIG_NFSD
-#define NFSSERVCTL sys_nfsservctl
-#else
-#define NFSSERVCTL sys_ni_syscall
-#endif
-
-extern syscall_handler_t um_mount;
-extern syscall_handler_t um_time;
-extern syscall_handler_t um_stime;
-
-#define LAST_GENERIC_SYSCALL __NR_set_tid_address
-
-#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
-#define LAST_SYSCALL LAST_GENERIC_SYSCALL
-#else
-#define LAST_SYSCALL LAST_ARCH_SYSCALL
-#endif
+extern syscall_handler_t sys_timer_create;
+extern syscall_handler_t old_mmap_i386;
+extern syscall_handler_t old_select;
+extern syscall_handler_t sys_modify_ldt;
+extern syscall_handler_t sys_rt_sigsuspend;
syscall_handler_t *sys_call_table[] = {
- [ __NR_restart_syscall ] = sys_restart_syscall,
- [ __NR_exit ] = sys_exit,
- [ __NR_fork ] = sys_fork,
+ [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall,
+ [ __NR_exit ] (syscall_handler_t *) sys_exit,
+ [ __NR_fork ] (syscall_handler_t *) sys_fork,
[ __NR_read ] = (syscall_handler_t *) sys_read,
[ __NR_write ] = (syscall_handler_t *) sys_write,
@@ -266,229 +64,249 @@ syscall_handler_t *sys_call_table[] = {
[ __NR_open ] = (syscall_handler_t *) sys_open,
[ __NR_close ] = (syscall_handler_t *) sys_close,
[ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid,
- [ __NR_creat ] = sys_creat,
- [ __NR_link ] = sys_link,
- [ __NR_unlink ] = sys_unlink,
+ [ __NR_creat ] (syscall_handler_t *) sys_creat,
+ [ __NR_link ] (syscall_handler_t *) sys_link,
+ [ __NR_unlink ] (syscall_handler_t *) sys_unlink,
[ __NR_execve ] = (syscall_handler_t *) sys_execve,
/* declared differently in kern_util.h */
- [ __NR_chdir ] = sys_chdir,
+ [ __NR_chdir ] (syscall_handler_t *) sys_chdir,
[ __NR_time ] = um_time,
- [ __NR_mknod ] = sys_mknod,
- [ __NR_chmod ] = sys_chmod,
- [ __NR_lchown ] = sys_lchown16,
- [ __NR_break ] = sys_ni_syscall,
- [ __NR_oldstat ] = sys_stat,
+ [ __NR_mknod ] (syscall_handler_t *) sys_mknod,
+ [ __NR_chmod ] (syscall_handler_t *) sys_chmod,
+ [ __NR_lchown ] (syscall_handler_t *) sys_lchown16,
+ [ __NR_break ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_oldstat ] (syscall_handler_t *) sys_stat,
[ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
- [ __NR_getpid ] = sys_getpid,
+ [ __NR_getpid ] (syscall_handler_t *) sys_getpid,
[ __NR_mount ] = um_mount,
- [ __NR_umount ] = sys_oldumount,
- [ __NR_setuid ] = sys_setuid16,
- [ __NR_getuid ] = sys_getuid16,
+ [ __NR_umount ] (syscall_handler_t *) sys_oldumount,
+ [ __NR_setuid ] (syscall_handler_t *) sys_setuid16,
+ [ __NR_getuid ] (syscall_handler_t *) sys_getuid16,
[ __NR_stime ] = um_stime,
- [ __NR_ptrace ] = sys_ptrace,
- [ __NR_alarm ] = sys_alarm,
- [ __NR_oldfstat ] = sys_fstat,
- [ __NR_pause ] = sys_pause,
- [ __NR_utime ] = sys_utime,
- [ __NR_stty ] = sys_ni_syscall,
- [ __NR_gtty ] = sys_ni_syscall,
- [ __NR_access ] = sys_access,
- [ __NR_nice ] = sys_nice,
- [ __NR_ftime ] = sys_ni_syscall,
- [ __NR_sync ] = sys_sync,
- [ __NR_kill ] = sys_kill,
- [ __NR_rename ] = sys_rename,
- [ __NR_mkdir ] = sys_mkdir,
- [ __NR_rmdir ] = sys_rmdir,
+ [ __NR_ptrace ] (syscall_handler_t *) sys_ptrace,
+ [ __NR_alarm ] (syscall_handler_t *) sys_alarm,
+ [ __NR_oldfstat ] (syscall_handler_t *) sys_fstat,
+ [ __NR_pause ] (syscall_handler_t *) sys_pause,
+ [ __NR_utime ] (syscall_handler_t *) sys_utime,
+ [ __NR_stty ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_gtty ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_access ] (syscall_handler_t *) sys_access,
+ [ __NR_nice ] (syscall_handler_t *) sys_nice,
+ [ __NR_ftime ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_sync ] (syscall_handler_t *) sys_sync,
+ [ __NR_kill ] (syscall_handler_t *) sys_kill,
+ [ __NR_rename ] (syscall_handler_t *) sys_rename,
+ [ __NR_mkdir ] (syscall_handler_t *) sys_mkdir,
+ [ __NR_rmdir ] (syscall_handler_t *) sys_rmdir,
/* Declared differently in asm/unistd.h */
[ __NR_dup ] = (syscall_handler_t *) sys_dup,
- [ __NR_pipe ] = sys_pipe,
- [ __NR_times ] = sys_times,
- [ __NR_prof ] = sys_ni_syscall,
- [ __NR_brk ] = sys_brk,
- [ __NR_setgid ] = sys_setgid16,
- [ __NR_getgid ] = sys_getgid16,
- [ __NR_signal ] = sys_signal,
- [ __NR_geteuid ] = sys_geteuid16,
- [ __NR_getegid ] = sys_getegid16,
- [ __NR_acct ] = sys_acct,
- [ __NR_umount2 ] = sys_umount,
- [ __NR_lock ] = sys_ni_syscall,
- [ __NR_ioctl ] = sys_ioctl,
- [ __NR_fcntl ] = sys_fcntl,
- [ __NR_mpx ] = sys_ni_syscall,
- [ __NR_setpgid ] = sys_setpgid,
- [ __NR_ulimit ] = sys_ni_syscall,
- [ __NR_oldolduname ] = sys_olduname,
- [ __NR_umask ] = sys_umask,
- [ __NR_chroot ] = sys_chroot,
- [ __NR_ustat ] = sys_ustat,
- [ __NR_dup2 ] = sys_dup2,
- [ __NR_getppid ] = sys_getppid,
- [ __NR_getpgrp ] = sys_getpgrp,
+ [ __NR_pipe ] (syscall_handler_t *) sys_pipe,
+ [ __NR_times ] (syscall_handler_t *) sys_times,
+ [ __NR_prof ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_brk ] (syscall_handler_t *) sys_brk,
+ [ __NR_setgid ] (syscall_handler_t *) sys_setgid16,
+ [ __NR_getgid ] (syscall_handler_t *) sys_getgid16,
+ [ __NR_signal ] (syscall_handler_t *) sys_signal,
+ [ __NR_geteuid ] (syscall_handler_t *) sys_geteuid16,
+ [ __NR_getegid ] (syscall_handler_t *) sys_getegid16,
+ [ __NR_acct ] (syscall_handler_t *) sys_acct,
+ [ __NR_umount2 ] (syscall_handler_t *) sys_umount,
+ [ __NR_lock ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_ioctl ] (syscall_handler_t *) sys_ioctl,
+ [ __NR_fcntl ] (syscall_handler_t *) sys_fcntl,
+ [ __NR_mpx ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_setpgid ] (syscall_handler_t *) sys_setpgid,
+ [ __NR_ulimit ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_oldolduname ] (syscall_handler_t *) sys_olduname,
+ [ __NR_umask ] (syscall_handler_t *) sys_umask,
+ [ __NR_chroot ] (syscall_handler_t *) sys_chroot,
+ [ __NR_ustat ] (syscall_handler_t *) sys_ustat,
+ [ __NR_dup2 ] (syscall_handler_t *) sys_dup2,
+ [ __NR_getppid ] (syscall_handler_t *) sys_getppid,
+ [ __NR_getpgrp ] (syscall_handler_t *) sys_getpgrp,
[ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
- [ __NR_sigaction ] = sys_sigaction,
- [ __NR_sgetmask ] = sys_sgetmask,
- [ __NR_ssetmask ] = sys_ssetmask,
- [ __NR_setreuid ] = sys_setreuid16,
- [ __NR_setregid ] = sys_setregid16,
- [ __NR_sigsuspend ] = sys_sigsuspend,
- [ __NR_sigpending ] = sys_sigpending,
- [ __NR_sethostname ] = sys_sethostname,
- [ __NR_setrlimit ] = sys_setrlimit,
- [ __NR_getrlimit ] = sys_old_getrlimit,
- [ __NR_getrusage ] = sys_getrusage,
- [ __NR_gettimeofday ] = sys_gettimeofday,
- [ __NR_settimeofday ] = sys_settimeofday,
- [ __NR_getgroups ] = sys_getgroups16,
- [ __NR_setgroups ] = sys_setgroups16,
- [ __NR_symlink ] = sys_symlink,
- [ __NR_oldlstat ] = sys_lstat,
- [ __NR_readlink ] = sys_readlink,
- [ __NR_uselib ] = sys_uselib,
+ [ __NR_sigaction ] (syscall_handler_t *) sys_sigaction,
+ [ __NR_sgetmask ] (syscall_handler_t *) sys_sgetmask,
+ [ __NR_ssetmask ] (syscall_handler_t *) sys_ssetmask,
+ [ __NR_setreuid ] (syscall_handler_t *) sys_setreuid16,
+ [ __NR_setregid ] (syscall_handler_t *) sys_setregid16,
+ [ __NR_sigsuspend ] (syscall_handler_t *) sys_sigsuspend,
+ [ __NR_sigpending ] (syscall_handler_t *) sys_sigpending,
+ [ __NR_sethostname ] (syscall_handler_t *) sys_sethostname,
+ [ __NR_setrlimit ] (syscall_handler_t *) sys_setrlimit,
+ [ __NR_getrlimit ] (syscall_handler_t *) sys_old_getrlimit,
+ [ __NR_getrusage ] (syscall_handler_t *) sys_getrusage,
+ [ __NR_gettimeofday ] (syscall_handler_t *) sys_gettimeofday,
+ [ __NR_settimeofday ] (syscall_handler_t *) sys_settimeofday,
+ [ __NR_getgroups ] (syscall_handler_t *) sys_getgroups16,
+ [ __NR_setgroups ] (syscall_handler_t *) sys_setgroups16,
+ [ __NR_symlink ] (syscall_handler_t *) sys_symlink,
+ [ __NR_oldlstat ] (syscall_handler_t *) sys_lstat,
+ [ __NR_readlink ] (syscall_handler_t *) sys_readlink,
+ [ __NR_uselib ] (syscall_handler_t *) sys_uselib,
[ __NR_swapon ] = (syscall_handler_t *) sys_swapon,
- [ __NR_reboot ] = sys_reboot,
+ [ __NR_reboot ] (syscall_handler_t *) sys_reboot,
[ __NR_readdir ] = old_readdir,
- [ __NR_munmap ] = sys_munmap,
- [ __NR_truncate ] = sys_truncate,
- [ __NR_ftruncate ] = sys_ftruncate,
- [ __NR_fchmod ] = sys_fchmod,
- [ __NR_fchown ] = sys_fchown16,
- [ __NR_getpriority ] = sys_getpriority,
- [ __NR_setpriority ] = sys_setpriority,
- [ __NR_profil ] = sys_ni_syscall,
- [ __NR_statfs ] = sys_statfs,
- [ __NR_fstatfs ] = sys_fstatfs,
- [ __NR_ioperm ] = sys_ni_syscall,
- [ __NR_socketcall ] = sys_socketcall,
- [ __NR_syslog ] = sys_syslog,
- [ __NR_setitimer ] = sys_setitimer,
- [ __NR_getitimer ] = sys_getitimer,
- [ __NR_stat ] = sys_newstat,
- [ __NR_lstat ] = sys_newlstat,
- [ __NR_fstat ] = sys_newfstat,
- [ __NR_olduname ] = sys_uname,
- [ __NR_iopl ] = sys_ni_syscall,
- [ __NR_vhangup ] = sys_vhangup,
- [ __NR_idle ] = sys_ni_syscall,
+ [ __NR_munmap ] (syscall_handler_t *) sys_munmap,
+ [ __NR_truncate ] (syscall_handler_t *) sys_truncate,
+ [ __NR_ftruncate ] (syscall_handler_t *) sys_ftruncate,
+ [ __NR_fchmod ] (syscall_handler_t *) sys_fchmod,
+ [ __NR_fchown ] (syscall_handler_t *) sys_fchown16,
+ [ __NR_getpriority ] (syscall_handler_t *) sys_getpriority,
+ [ __NR_setpriority ] (syscall_handler_t *) sys_setpriority,
+ [ __NR_profil ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_statfs ] (syscall_handler_t *) sys_statfs,
+ [ __NR_fstatfs ] (syscall_handler_t *) sys_fstatfs,
+ [ __NR_ioperm ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_socketcall ] (syscall_handler_t *) sys_socketcall,
+ [ __NR_syslog ] (syscall_handler_t *) sys_syslog,
+ [ __NR_setitimer ] (syscall_handler_t *) sys_setitimer,
+ [ __NR_getitimer ] (syscall_handler_t *) sys_getitimer,
+ [ __NR_stat ] (syscall_handler_t *) sys_newstat,
+ [ __NR_lstat ] (syscall_handler_t *) sys_newlstat,
+ [ __NR_fstat ] (syscall_handler_t *) sys_newfstat,
+ [ __NR_olduname ] (syscall_handler_t *) sys_uname,
+ [ __NR_iopl ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_vhangup ] (syscall_handler_t *) sys_vhangup,
+ [ __NR_idle ] (syscall_handler_t *) sys_ni_syscall,
[ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
[ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff,
- [ __NR_sysinfo ] = sys_sysinfo,
- [ __NR_ipc ] = sys_ipc,
- [ __NR_fsync ] = sys_fsync,
- [ __NR_sigreturn ] = sys_sigreturn,
- [ __NR_clone ] = sys_clone,
- [ __NR_setdomainname ] = sys_setdomainname,
- [ __NR_uname ] = sys_newuname,
- [ __NR_adjtimex ] = sys_adjtimex,
- [ __NR_mprotect ] = sys_mprotect,
- [ __NR_sigprocmask ] = sys_sigprocmask,
- [ __NR_create_module ] = sys_ni_syscall,
- [ __NR_init_module ] = sys_init_module,
- [ __NR_delete_module ] = sys_delete_module,
- [ __NR_get_kernel_syms ] = sys_ni_syscall,
- [ __NR_quotactl ] = sys_quotactl,
- [ __NR_getpgid ] = sys_getpgid,
- [ __NR_fchdir ] = sys_fchdir,
- [ __NR_bdflush ] = sys_bdflush,
- [ __NR_sysfs ] = sys_sysfs,
- [ __NR_personality ] = sys_personality,
- [ __NR_afs_syscall ] = sys_ni_syscall,
- [ __NR_setfsuid ] = sys_setfsuid16,
- [ __NR_setfsgid ] = sys_setfsgid16,
- [ __NR__llseek ] = sys_llseek,
- [ __NR_getdents ] = sys_getdents,
+ [ __NR_sysinfo ] (syscall_handler_t *) sys_sysinfo,
+ [ __NR_ipc ] (syscall_handler_t *) sys_ipc,
+ [ __NR_fsync ] (syscall_handler_t *) sys_fsync,
+ [ __NR_sigreturn ] (syscall_handler_t *) sys_sigreturn,
+ [ __NR_clone ] (syscall_handler_t *) sys_clone,
+ [ __NR_setdomainname ] (syscall_handler_t *) sys_setdomainname,
+ [ __NR_uname ] (syscall_handler_t *) sys_newuname,
+ [ __NR_adjtimex ] (syscall_handler_t *) sys_adjtimex,
+ [ __NR_mprotect ] (syscall_handler_t *) sys_mprotect,
+ [ __NR_sigprocmask ] (syscall_handler_t *) sys_sigprocmask,
+ [ __NR_create_module ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_init_module ] (syscall_handler_t *) sys_init_module,
+ [ __NR_delete_module ] (syscall_handler_t *) sys_delete_module,
+ [ __NR_get_kernel_syms ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_quotactl ] (syscall_handler_t *) sys_quotactl,
+ [ __NR_getpgid ] (syscall_handler_t *) sys_getpgid,
+ [ __NR_fchdir ] (syscall_handler_t *) sys_fchdir,
+ [ __NR_bdflush ] (syscall_handler_t *) sys_bdflush,
+ [ __NR_sysfs ] (syscall_handler_t *) sys_sysfs,
+ [ __NR_personality ] (syscall_handler_t *) sys_personality,
+ [ __NR_afs_syscall ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_setfsuid ] (syscall_handler_t *) sys_setfsuid16,
+ [ __NR_setfsgid ] (syscall_handler_t *) sys_setfsgid16,
+ [ __NR__llseek ] (syscall_handler_t *) sys_llseek,
+ [ __NR_getdents ] (syscall_handler_t *) sys_getdents,
[ __NR__newselect ] = (syscall_handler_t *) sys_select,
- [ __NR_flock ] = sys_flock,
- [ __NR_msync ] = sys_msync,
- [ __NR_readv ] = sys_readv,
- [ __NR_writev ] = sys_writev,
- [ __NR_getsid ] = sys_getsid,
- [ __NR_fdatasync ] = sys_fdatasync,
+ [ __NR_flock ] (syscall_handler_t *) sys_flock,
+ [ __NR_msync ] (syscall_handler_t *) sys_msync,
+ [ __NR_readv ] (syscall_handler_t *) sys_readv,
+ [ __NR_writev ] (syscall_handler_t *) sys_writev,
+ [ __NR_getsid ] (syscall_handler_t *) sys_getsid,
+ [ __NR_fdatasync ] (syscall_handler_t *) sys_fdatasync,
[ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl,
- [ __NR_mlock ] = sys_mlock,
- [ __NR_munlock ] = sys_munlock,
- [ __NR_mlockall ] = sys_mlockall,
- [ __NR_munlockall ] = sys_munlockall,
- [ __NR_sched_setparam ] = sys_sched_setparam,
- [ __NR_sched_getparam ] = sys_sched_getparam,
- [ __NR_sched_setscheduler ] = sys_sched_setscheduler,
- [ __NR_sched_getscheduler ] = sys_sched_getscheduler,
+ [ __NR_mlock ] (syscall_handler_t *) sys_mlock,
+ [ __NR_munlock ] (syscall_handler_t *) sys_munlock,
+ [ __NR_mlockall ] (syscall_handler_t *) sys_mlockall,
+ [ __NR_munlockall ] (syscall_handler_t *) sys_munlockall,
+ [ __NR_sched_setparam ] (syscall_handler_t *) sys_sched_setparam,
+ [ __NR_sched_getparam ] (syscall_handler_t *) sys_sched_getparam,
+ [ __NR_sched_setscheduler ] (syscall_handler_t *) sys_sched_setscheduler,
+ [ __NR_sched_getscheduler ] (syscall_handler_t *) sys_sched_getscheduler,
[ __NR_sched_yield ] = (syscall_handler_t *) yield,
- [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max,
- [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min,
- [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval,
- [ __NR_nanosleep ] = sys_nanosleep,
- [ __NR_mremap ] = sys_mremap,
- [ __NR_setresuid ] = sys_setresuid16,
- [ __NR_getresuid ] = sys_getresuid16,
- [ __NR_vm86 ] = sys_ni_syscall,
- [ __NR_query_module ] = sys_ni_syscall,
- [ __NR_poll ] = sys_poll,
- [ __NR_nfsservctl ] = NFSSERVCTL,
- [ __NR_setresgid ] = sys_setresgid16,
- [ __NR_getresgid ] = sys_getresgid16,
- [ __NR_prctl ] = sys_prctl,
- [ __NR_rt_sigreturn ] = sys_rt_sigreturn,
- [ __NR_rt_sigaction ] = sys_rt_sigaction,
- [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask,
- [ __NR_rt_sigpending ] = sys_rt_sigpending,
- [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait,
- [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo,
- [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend,
- [ __NR_pread64 ] = sys_pread64,
- [ __NR_pwrite64 ] = sys_pwrite64,
- [ __NR_chown ] = sys_chown16,
- [ __NR_getcwd ] = sys_getcwd,
- [ __NR_capget ] = sys_capget,
- [ __NR_capset ] = sys_capset,
- [ __NR_sigaltstack ] = sys_sigaltstack,
- [ __NR_sendfile ] = sys_sendfile,
- [ __NR_getpmsg ] = sys_ni_syscall,
- [ __NR_putpmsg ] = sys_ni_syscall,
- [ __NR_vfork ] = sys_vfork,
- [ __NR_ugetrlimit ] = sys_getrlimit,
- [ __NR_mmap2 ] = sys_mmap2,
- [ __NR_truncate64 ] = sys_truncate64,
- [ __NR_ftruncate64 ] = sys_ftruncate64,
- [ __NR_stat64 ] = sys_stat64,
- [ __NR_lstat64 ] = sys_lstat64,
- [ __NR_fstat64 ] = sys_fstat64,
- [ __NR_fcntl64 ] = sys_fcntl64,
- [ __NR_getdents64 ] = sys_getdents64,
- [ __NR_gettid ] = sys_gettid,
- [ __NR_readahead ] = sys_readahead,
- [ __NR_setxattr ] = sys_ni_syscall,
- [ __NR_lsetxattr ] = sys_ni_syscall,
- [ __NR_fsetxattr ] = sys_ni_syscall,
- [ __NR_getxattr ] = sys_ni_syscall,
- [ __NR_lgetxattr ] = sys_ni_syscall,
- [ __NR_fgetxattr ] = sys_ni_syscall,
- [ __NR_listxattr ] = sys_ni_syscall,
- [ __NR_llistxattr ] = sys_ni_syscall,
- [ __NR_flistxattr ] = sys_ni_syscall,
- [ __NR_removexattr ] = sys_ni_syscall,
- [ __NR_lremovexattr ] = sys_ni_syscall,
- [ __NR_fremovexattr ] = sys_ni_syscall,
- [ __NR_tkill ] = sys_tkill,
- [ __NR_sendfile64 ] = sys_sendfile64,
- [ __NR_futex ] = sys_futex,
- [ __NR_sched_setaffinity ] = sys_sched_setaffinity,
- [ __NR_sched_getaffinity ] = sys_sched_getaffinity,
- [ __NR_io_setup ] = sys_io_setup,
- [ __NR_io_destroy ] = sys_io_destroy,
- [ __NR_io_getevents ] = sys_io_getevents,
- [ __NR_io_submit ] = sys_io_submit,
- [ __NR_io_cancel ] = sys_io_cancel,
- [ __NR_exit_group ] = sys_exit_group,
- [ __NR_lookup_dcookie ] = sys_lookup_dcookie,
- [ __NR_epoll_create ] = sys_epoll_create,
- [ __NR_epoll_ctl ] = sys_epoll_ctl,
- [ __NR_epoll_wait ] = sys_epoll_wait,
- [ __NR_remap_file_pages ] = sys_remap_file_pages,
- [ __NR_set_tid_address ] = sys_set_tid_address,
+ [ __NR_sched_get_priority_max ] (syscall_handler_t *) sys_sched_get_priority_max,
+ [ __NR_sched_get_priority_min ] (syscall_handler_t *) sys_sched_get_priority_min,
+ [ __NR_sched_rr_get_interval ] (syscall_handler_t *) sys_sched_rr_get_interval,
+ [ __NR_nanosleep ] (syscall_handler_t *) sys_nanosleep,
+ [ __NR_mremap ] (syscall_handler_t *) sys_mremap,
+ [ __NR_setresuid ] (syscall_handler_t *) sys_setresuid16,
+ [ __NR_getresuid ] (syscall_handler_t *) sys_getresuid16,
+ [ __NR_vm86 ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_query_module ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_poll ] (syscall_handler_t *) sys_poll,
+ [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL,
+ [ __NR_setresgid ] (syscall_handler_t *) sys_setresgid16,
+ [ __NR_getresgid ] (syscall_handler_t *) sys_getresgid16,
+ [ __NR_prctl ] (syscall_handler_t *) sys_prctl,
+ [ __NR_rt_sigreturn ] (syscall_handler_t *) sys_rt_sigreturn,
+ [ __NR_rt_sigaction ] (syscall_handler_t *) sys_rt_sigaction,
+ [ __NR_rt_sigprocmask ] (syscall_handler_t *) sys_rt_sigprocmask,
+ [ __NR_rt_sigpending ] (syscall_handler_t *) sys_rt_sigpending,
+ [ __NR_rt_sigtimedwait ] (syscall_handler_t *) sys_rt_sigtimedwait,
+ [ __NR_rt_sigqueueinfo ] (syscall_handler_t *) sys_rt_sigqueueinfo,
+ [ __NR_rt_sigsuspend ] (syscall_handler_t *) sys_rt_sigsuspend,
+ [ __NR_pread64 ] (syscall_handler_t *) sys_pread64,
+ [ __NR_pwrite64 ] (syscall_handler_t *) sys_pwrite64,
+ [ __NR_chown ] (syscall_handler_t *) sys_chown16,
+ [ __NR_getcwd ] (syscall_handler_t *) sys_getcwd,
+ [ __NR_capget ] (syscall_handler_t *) sys_capget,
+ [ __NR_capset ] (syscall_handler_t *) sys_capset,
+ [ __NR_sigaltstack ] (syscall_handler_t *) sys_sigaltstack,
+ [ __NR_sendfile ] (syscall_handler_t *) sys_sendfile,
+ [ __NR_getpmsg ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_putpmsg ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_vfork ] (syscall_handler_t *) sys_vfork,
+ [ __NR_ugetrlimit ] (syscall_handler_t *) sys_getrlimit,
+ [ __NR_mmap2 ] (syscall_handler_t *) sys_mmap2,
+ [ __NR_truncate64 ] (syscall_handler_t *) sys_truncate64,
+ [ __NR_ftruncate64 ] (syscall_handler_t *) sys_ftruncate64,
+ [ __NR_stat64 ] (syscall_handler_t *) sys_stat64,
+ [ __NR_lstat64 ] (syscall_handler_t *) sys_lstat64,
+ [ __NR_fstat64 ] (syscall_handler_t *) sys_fstat64,
+ [ __NR_getdents64 ] (syscall_handler_t *) sys_getdents64,
+ [ __NR_fcntl64 ] (syscall_handler_t *) sys_fcntl64,
+ [ 223 ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_gettid ] (syscall_handler_t *) sys_gettid,
+ [ __NR_readahead ] (syscall_handler_t *) sys_readahead,
+ [ __NR_setxattr ] (syscall_handler_t *) sys_setxattr,
+ [ __NR_lsetxattr ] (syscall_handler_t *) sys_lsetxattr,
+ [ __NR_fsetxattr ] (syscall_handler_t *) sys_fsetxattr,
+ [ __NR_getxattr ] (syscall_handler_t *) sys_getxattr,
+ [ __NR_lgetxattr ] (syscall_handler_t *) sys_lgetxattr,
+ [ __NR_fgetxattr ] (syscall_handler_t *) sys_fgetxattr,
+ [ __NR_listxattr ] (syscall_handler_t *) sys_listxattr,
+ [ __NR_llistxattr ] (syscall_handler_t *) sys_llistxattr,
+ [ __NR_flistxattr ] (syscall_handler_t *) sys_flistxattr,
+ [ __NR_removexattr ] (syscall_handler_t *) sys_removexattr,
+ [ __NR_lremovexattr ] (syscall_handler_t *) sys_lremovexattr,
+ [ __NR_fremovexattr ] (syscall_handler_t *) sys_fremovexattr,
+ [ __NR_tkill ] (syscall_handler_t *) sys_tkill,
+ [ __NR_sendfile64 ] (syscall_handler_t *) sys_sendfile64,
+ [ __NR_futex ] (syscall_handler_t *) sys_futex,
+ [ __NR_sched_setaffinity ] (syscall_handler_t *) sys_sched_setaffinity,
+ [ __NR_sched_getaffinity ] (syscall_handler_t *) sys_sched_getaffinity,
+ [ __NR_set_thread_area ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_get_thread_area ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_io_setup ] (syscall_handler_t *) sys_io_setup,
+ [ __NR_io_destroy ] (syscall_handler_t *) sys_io_destroy,
+ [ __NR_io_getevents ] (syscall_handler_t *) sys_io_getevents,
+ [ __NR_io_submit ] (syscall_handler_t *) sys_io_submit,
+ [ __NR_io_cancel ] (syscall_handler_t *) sys_io_cancel,
+ [ __NR_fadvise64 ] (syscall_handler_t *) sys_fadvise64,
+ [ 251 ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_exit_group ] (syscall_handler_t *) sys_exit_group,
+ [ __NR_lookup_dcookie ] (syscall_handler_t *) sys_lookup_dcookie,
+ [ __NR_epoll_create ] (syscall_handler_t *) sys_epoll_create,
+ [ __NR_epoll_ctl ] (syscall_handler_t *) sys_epoll_ctl,
+ [ __NR_epoll_wait ] (syscall_handler_t *) sys_epoll_wait,
+ [ __NR_remap_file_pages ] (syscall_handler_t *) sys_remap_file_pages,
+ [ __NR_set_tid_address ] (syscall_handler_t *) sys_set_tid_address,
+ [ __NR_timer_create ] (syscall_handler_t *) sys_timer_create,
+ [ __NR_timer_settime ] (syscall_handler_t *) sys_timer_settime,
+ [ __NR_timer_gettime ] (syscall_handler_t *) sys_timer_gettime,
+ [ __NR_timer_getoverrun ] (syscall_handler_t *) sys_timer_getoverrun,
+ [ __NR_timer_delete ] (syscall_handler_t *) sys_timer_delete,
+ [ __NR_clock_settime ] (syscall_handler_t *) sys_clock_settime,
+ [ __NR_clock_gettime ] (syscall_handler_t *) sys_clock_gettime,
+ [ __NR_clock_getres ] (syscall_handler_t *) sys_clock_getres,
+ [ __NR_clock_nanosleep ] (syscall_handler_t *) sys_clock_nanosleep,
+ [ __NR_statfs64 ] (syscall_handler_t *) sys_statfs64,
+ [ __NR_fstatfs64 ] (syscall_handler_t *) sys_fstatfs64,
+ [ __NR_tgkill ] (syscall_handler_t *) sys_tgkill,
+ [ __NR_utimes ] (syscall_handler_t *) sys_utimes,
+ [ __NR_fadvise64_64 ] (syscall_handler_t *) sys_fadvise64_64,
+ [ __NR_vserver ] (syscall_handler_t *) sys_ni_syscall,
ARCH_SYSCALLS
[ LAST_SYSCALL + 1 ... NR_syscalls ] =
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
index 2af5fc2e569a6..ba427339e3538 100644
--- a/arch/um/kernel/syscall_kern.c
+++ b/arch/um/kernel/syscall_kern.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -36,32 +36,34 @@ long um_mount(char * dev_name, char * dir_name, char * type,
long sys_fork(void)
{
- struct task_struct *p;
+ long ret;
current->thread.forking = 1;
- p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+ ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
current->thread.forking = 0;
- return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
+ return(ret);
}
-long sys_clone(unsigned long clone_flags, unsigned long newsp)
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+ int *parent_tid, int *child_tid)
{
- struct task_struct *p;
+ long ret;
current->thread.forking = 1;
- p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL);
+ ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
current->thread.forking = 0;
- return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
+ return(ret);
}
long sys_vfork(void)
{
- struct task_struct *p;
+ long ret;
current->thread.forking = 1;
- p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL);
+ ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL,
+ NULL);
current->thread.forking = 0;
- return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
+ return(ret);
}
/* common code for old and new mmaps */
@@ -136,43 +138,12 @@ int sys_pipe(unsigned long * fildes)
error = do_pipe(fd);
if (!error) {
- if (copy_to_user(fildes, fd, 2*sizeof(int)))
+ if (copy_to_user(fildes, fd, sizeof(fd)))
error = -EFAULT;
}
return error;
}
-int sys_sigaction(int sig, const struct old_sigaction *act,
- struct old_sigaction *oact)
-{
- struct k_sigaction new_ka, old_ka;
- int ret;
-
- if (act) {
- old_sigset_t mask;
- if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
- return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
- siginitset(&new_ka.sa.sa_mask, mask);
- }
-
- ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
- if (!ret && oact) {
- if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
- return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
- }
-
- return ret;
-}
-
/*
* sys_ipc() is the de-multiplexer for the SysV IPC calls..
*
@@ -254,7 +225,7 @@ int sys_ipc (uint call, int first, int second,
return sys_shmctl (first, second,
(struct shmid_ds *) ptr);
default:
- return -EINVAL;
+ return -ENOSYS;
}
}
@@ -303,11 +274,6 @@ int sys_olduname(struct oldold_utsname * name)
return error;
}
-int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
-{
- return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
-}
-
long execute_syscall(void *r)
{
return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index b43c214668e73..80b84700fa9e9 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -44,6 +44,11 @@ void dump_stack(void)
}
EXPORT_SYMBOL(dump_stack);
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+ show_trace(sp);
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c
index 3fd42081de8d3..b1674bc1395db 100644
--- a/arch/um/kernel/tempfile.c
+++ b/arch/um/kernel/tempfile.c
@@ -28,6 +28,7 @@ static void __init find_tempdir(void)
}
if((dir == NULL) || (*dir == '\0'))
dir = "/tmp";
+
tempdir = malloc(strlen(dir) + 2);
if(tempdir == NULL){
fprintf(stderr, "Failed to malloc tempdir, "
@@ -49,7 +50,8 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink)
else
*tempname = 0;
strcat(tempname, template);
- if((fd = mkstemp(tempname)) < 0){
+ fd = mkstemp(tempname);
+ if(fd < 0){
fprintf(stderr, "open - cannot create %s: %s\n", tempname,
strerror(errno));
return -1;
@@ -59,7 +61,8 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink)
return -1;
}
if(out_tempname){
- if((*out_tempname = strdup(tempname)) == NULL){
+ *out_tempname = strdup(tempname);
+ if(*out_tempname == NULL){
perror("strdup");
return -1;
}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 6f0d7573e46ce..cb7ec3736a170 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -4,24 +4,34 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
-#include "linux/module.h"
+#include <string.h>
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "process.h"
#include "signal_user.h"
#include "time_user.h"
+#include "kern_constants.h"
+
+/* XXX This really needs to be declared and initialized in a kernel file since
+ * it's in <linux/time.h>
+ */
+extern struct timespec wall_to_monotonic;
extern struct timeval xtime;
+struct timeval local_offset = { 0, 0 };
+
void timer(void)
{
gettimeofday(&xtime, NULL);
+ timeradd(&xtime, &local_offset, &xtime);
}
void set_interval(int timer_type)
@@ -66,7 +76,7 @@ void switch_timers(int to_real)
errno);
}
-void idle_timer(void)
+void uml_idle_timer(void)
{
if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
panic("Couldn't unset SIGVTALRM handler");
@@ -76,14 +86,60 @@ void idle_timer(void)
set_interval(ITIMER_REAL);
}
+static unsigned long long get_host_hz(void)
+{
+ char mhzline[16], *end;
+ unsigned long long mhz;
+ int ret, mult, rest, len;
+
+ ret = cpu_feature("cpu MHz", mhzline,
+ sizeof(mhzline) / sizeof(mhzline[0]));
+ if(!ret)
+ panic ("Could not get host MHZ");
+
+ mhz = strtoul(mhzline, &end, 10);
+
+ /* This business is to parse a floating point number without using
+ * floating types.
+ */
+
+ rest = 0;
+ mult = 0;
+ if(*end == '.'){
+ end++;
+ len = strlen(end);
+ if(len < 6)
+ mult = 6 - len;
+ else if(len > 6)
+ end[6] = '\0';
+ rest = strtoul(end, NULL, 10);
+ while(mult-- > 0)
+ rest *= 10;
+ }
+
+ return(1000000 * mhz + rest);
+}
+
+unsigned long long host_hz = 0;
+
+extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
+
void time_init(void)
{
+ struct timespec now;
+
+ host_hz = get_host_hz();
if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
panic("Couldn't set SIGVTALRM handler");
set_interval(ITIMER_VIRTUAL);
+
+ do_posix_clock_monotonic_gettime(&now);
+ wall_to_monotonic.tv_sec = -now.tv_sec;
+ wall_to_monotonic.tv_nsec = -now.tv_nsec;
}
-struct timeval local_offset = { 0, 0 };
+/* Declared in linux/time.h, which can't be included here */
+extern void clock_was_set(void);
void do_gettimeofday(struct timeval *tv)
{
@@ -96,15 +152,13 @@ void do_gettimeofday(struct timeval *tv)
clock_was_set();
}
-EXPORT_SYMBOL(do_gettimeofday);
-
int do_settimeofday(struct timespec *tv)
{
struct timeval now;
unsigned long flags;
struct timeval tv_in;
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+ if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC)
return -EINVAL;
tv_in.tv_sec = tv->tv_sec;
@@ -114,9 +168,9 @@ int do_settimeofday(struct timespec *tv)
gettimeofday(&now, NULL);
timersub(&tv_in, &now, &local_offset);
time_unlock(flags);
-}
-EXPORT_SYMBOL(do_settimeofday);
+ return(0);
+}
void idle_sleep(int secs)
{
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 752fd03f2bcd6..e30c98023b159 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -30,22 +30,60 @@ int hz(void)
return(HZ);
}
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+ return (unsigned long long)jiffies_64 * (1000000000 / HZ);
+}
+
/* Changed at early boot */
int timer_irq_inited = 0;
-/* missed_ticks will be modified after kernel memory has been
- * write-protected, so this puts it in a section which will be left
- * write-enabled.
- */
-int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS];
+static int first_tick;
+static unsigned long long prev_tsc;
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
+static long long delta; /* Deviation per interval */
+#endif
+
+extern unsigned long long host_hz;
void timer_irq(union uml_pt_regs *regs)
{
- int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu];
+ unsigned long long ticks = 0;
+
+ if(!timer_irq_inited){
+ /* This is to ensure that ticks don't pile up when
+ * the timer handler is suspended */
+ first_tick = 0;
+ return;
+ }
+
+ if(first_tick){
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
+ unsigned long long tsc;
+ /* We've had 1 tick */
+ tsc = time_stamp();
- if(!timer_irq_inited) return;
- missed_ticks[cpu] = 0;
- while(ticks--) do_IRQ(TIMER_IRQ, regs);
+ delta += tsc - prev_tsc;
+ prev_tsc = tsc;
+
+ ticks += (delta * HZ) / host_hz;
+ delta -= (ticks * host_hz) / HZ;
+#else
+ ticks = 1;
+#endif
+ }
+ else {
+ prev_tsc = time_stamp();
+ first_tick = 1;
+ }
+
+ while(ticks > 0){
+ do_IRQ(TIMER_IRQ, regs);
+ ticks--;
+ }
}
void boot_timer_handler(int sig)
@@ -58,12 +96,15 @@ void boot_timer_handler(int sig)
do_timer(&regs);
}
-void um_timer(int irq, void *dev, struct pt_regs *regs)
+irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
{
+ unsigned long flags;
+
do_timer(regs);
- write_seqlock(&xtime_lock);
+ write_seqlock_irqsave(&xtime_lock, flags);
timer();
- write_sequnlock(&xtime_lock);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ return(IRQ_HANDLED);
}
long um_time(int * tloc)
@@ -81,12 +122,12 @@ long um_time(int * tloc)
long um_stime(int * tptr)
{
int value;
- struct timeval new;
+ struct timespec new;
if (get_user(value, tptr))
return -EFAULT;
new.tv_sec = value;
- new.tv_usec = 0;
+ new.tv_nsec = 0;
do_settimeofday(&new);
return 0;
}
@@ -125,9 +166,11 @@ void __const_udelay(um_udelay_t usecs)
void timer_handler(int sig, union uml_pt_regs *regs)
{
#ifdef CONFIG_SMP
+ local_irq_disable();
update_process_times(user_context(UPT_SP(regs)));
+ local_irq_enable();
#endif
- if(current->thread_info->cpu == 0)
+ if(current_thread->cpu == 0)
timer_irq(regs);
}
@@ -136,6 +179,7 @@ static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED;
unsigned long time_lock(void)
{
unsigned long flags;
+
spin_lock_irqsave(&timer_spinlock, flags);
return(flags);
}
@@ -150,8 +194,8 @@ int __init timer_init(void)
int err;
CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
- if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer",
- NULL)) != 0)
+ err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
+ if(err != 0)
printk(KERN_ERR "timer_init : request_irq failed - "
"errno = %d\n", -err);
timer_irq_inited = 1;
@@ -160,7 +204,6 @@ int __init timer_init(void)
__initcall(timer_init);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 7925dc459490c..cba33ef6da5d8 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -16,12 +16,15 @@
#include "asm/tlbflush.h"
#include "asm/a.out.h"
#include "asm/current.h"
+#include "asm/irq.h"
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
#include "chan_kern.h"
#include "mconsole_kern.h"
#include "2_5compat.h"
+#include "mem.h"
+#include "mem_kern.h"
int handle_page_fault(unsigned long address, unsigned long ip,
int is_write, int is_user, int *code_out)
@@ -51,12 +54,10 @@ int handle_page_fault(unsigned long address, unsigned long ip,
if(is_write && !(vma->vm_flags & VM_WRITE))
goto out;
page = address & PAGE_MASK;
- if(page == (unsigned long) current->thread_info + PAGE_SIZE)
- panic("Kernel stack overflow");
pgd = pgd_offset(mm, page);
pmd = pmd_offset(pgd, page);
- survive:
do {
+ survive:
switch (handle_mm_fault(mm, vma, address, is_write)){
case VM_FAULT_MINOR:
current->min_flt++;
@@ -75,10 +76,10 @@ int handle_page_fault(unsigned long address, unsigned long ip,
}
pte = pte_offset_kernel(pmd, page);
} while(!pte_present(*pte));
+ err = 0;
*pte = pte_mkyoung(*pte);
if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
flush_tlb_page(vma, page);
- err = 0;
out:
up_read(&mm->mmap_sem);
return(err);
@@ -94,10 +95,36 @@ out_of_memory:
down_read(&mm->mmap_sem);
goto survive;
}
- err = -ENOMEM;
goto out;
}
+LIST_HEAD(physmem_remappers);
+
+void register_remapper(struct remapper *info)
+{
+ list_add(&info->list, &physmem_remappers);
+}
+
+static int check_remapped_addr(unsigned long address, int is_write)
+{
+ struct remapper *remapper;
+ struct list_head *ele;
+ __u64 offset;
+ int fd;
+
+ fd = phys_mapping(__pa(address), &offset);
+ if(fd == -1)
+ return(0);
+
+ list_for_each(ele, &physmem_remappers){
+ remapper = list_entry(ele, struct remapper, list);
+ if((*remapper->proc)(fd, address, is_write, offset))
+ return(1);
+ }
+
+ return(0);
+}
+
unsigned long segv(unsigned long address, unsigned long ip, int is_write,
int is_user, void *sc)
{
@@ -109,7 +136,9 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
flush_tlb_kernel_vm();
return(0);
}
- if(current->mm == NULL)
+ else if(check_remapped_addr(address & PAGE_MASK, is_write))
+ return(0);
+ else if(current->mm == NULL)
panic("Segfault with no mm");
err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
@@ -120,9 +149,8 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
current->thread.fault_addr = (void *) address;
do_longjmp(catcher, 1);
}
- else if(current->thread.fault_addr != NULL){
+ else if(current->thread.fault_addr != NULL)
panic("fault_addr set but no fault catcher");
- }
else if(arch_fixup(ip, sc))
return(0);
@@ -155,8 +183,6 @@ void bad_segv(unsigned long address, unsigned long ip, int is_write)
{
struct siginfo si;
- printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx "
- "(ip 0x%lx)\n", current->comm, current->pid, address, ip);
si.si_signo = SIGSEGV;
si.si_code = SEGV_ACCERR;
si.si_addr = (void *) address;
@@ -180,6 +206,11 @@ void bus_handler(int sig, union uml_pt_regs *regs)
else relay_signal(sig, regs);
}
+void winch(int sig, union uml_pt_regs *regs)
+{
+ do_IRQ(WINCH_IRQ, regs);
+}
+
void trap_init(void)
{
}
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
index 63812e597f425..e806a8c6a836e 100644
--- a/arch/um/kernel/trap_user.c
+++ b/arch/um/kernel/trap_user.c
@@ -5,11 +5,9 @@
#include <stdlib.h>
#include <errno.h>
-#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/time.h>
-#include <sys/ioctl.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <asm/page.h>
@@ -34,7 +32,14 @@ void kill_child_dead(int pid)
{
kill(pid, SIGKILL);
kill(pid, SIGCONT);
- while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
+ do {
+ int n;
+ CATCH_EINTR(n = waitpid(pid, NULL, 0));
+ if (n > 0)
+ kill(pid, SIGCONT);
+ else
+ break;
+ } while(1);
}
/* Unlocked - don't care if this is a bit off */
@@ -82,6 +87,8 @@ struct signal_info sig_info[] = {
.is_irq = 0 },
[ SIGILL ] { .handler = relay_signal,
.is_irq = 0 },
+ [ SIGWINCH ] { .handler = winch,
+ .is_irq = 1 },
[ SIGBUS ] { .handler = bus_handler,
.is_irq = 0 },
[ SIGSEGV] { .handler = segv_handler,
@@ -102,12 +109,11 @@ void sig_handler(int sig, struct sigcontext sc)
sig, &sc);
}
-extern int timer_irq_inited, missed_ticks[];
+extern int timer_irq_inited;
void alarm_handler(int sig, struct sigcontext sc)
{
if(!timer_irq_inited) return;
- missed_ticks[cpu()]++;
if(sig == SIGALRM)
switch_timers(0);
@@ -123,7 +129,7 @@ void do_longjmp(void *b, int val)
{
jmp_buf *buf = b;
- longjmp(*buf, val);
+ siglongjmp(*buf, val);
}
/*
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
index 439688b0d9e60..33416e889e5c0 100644
--- a/arch/um/kernel/tt/Makefile
+++ b/arch/um/kernel/tt/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
# Licensed under the GPL
#
@@ -7,7 +7,7 @@ extra-y := unmap_fin.o
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 \
- uaccess_user.o sys-$(SUBARCH)/
+ uaccess.o uaccess_user.o sys-$(SUBARCH)/
obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
@@ -27,5 +27,3 @@ $(obj)/unmap.o: $(src)/unmap.c
$(obj)/unmap_fin.o : $(src)/unmap.o
ld -r -o $@ $< -lc -L/usr/lib
-
-clean :
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
index afd94713d7422..d8e3bfe6b8820 100644
--- a/arch/um/kernel/tt/exec_kern.c
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -17,6 +17,7 @@
#include "mem_user.h"
#include "os.h"
#include "tlb.h"
+#include "mode.h"
static int exec_tramp(void *sig_stack)
{
@@ -47,17 +48,17 @@ void flush_thread_tt(void)
do_exit(SIGKILL);
}
- if(current->thread_info->cpu == 0)
+ if(current_thread->cpu == 0)
forward_interrupts(new_pid);
current->thread.request.op = OP_EXEC;
current->thread.request.u.exec.pid = new_pid;
- unprotect_stack((unsigned long) current->thread_info);
+ unprotect_stack((unsigned long) current_thread);
os_usr1_process(os_getpid());
enable_timer();
free_page(stack);
protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
- task_protections((unsigned long) current->thread_info);
+ task_protections((unsigned long) current_thread);
force_flush_all();
unblock_signals();
}
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
index 35d108266d41d..6d5fa825a42da 100644
--- a/arch/um/kernel/tt/exec_user.c
+++ b/arch/um/kernel/tt/exec_user.c
@@ -19,13 +19,18 @@
void do_exec(int old_pid, int new_pid)
{
unsigned long regs[FRAME_SIZE];
+ int err;
if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
- (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) ||
- (waitpid(new_pid, 0, WUNTRACED) < 0))
+ (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
tracer_panic("do_exec failed to attach proc - errno = %d",
errno);
+ CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
+ if (err < 0)
+ tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
+ errno);
+
if(ptrace_getregs(old_pid, regs) < 0)
tracer_panic("do_exec failed to get registers - errno = %d",
errno);
diff --git a/arch/um/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h
index 83d94abb90436..1a64e753ea966 100644
--- a/arch/um/kernel/tt/include/mode.h
+++ b/arch/um/kernel/tt/include/mode.h
@@ -8,6 +8,8 @@
#include "sysdep/ptrace.h"
+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);
diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h
index 42425a2253c6c..7399836cb8d81 100644
--- a/arch/um/kernel/tt/include/uaccess.h
+++ b/arch/um/kernel/tt/include/uaccess.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -43,65 +43,19 @@ extern unsigned long get_fault_addr(void);
extern int __do_copy_from_user(void *to, const void *from, int n,
void **fault_addr, void **fault_catcher);
-
-static inline int copy_from_user_tt(void *to, const void *from, int n)
-{
- return(access_ok_tt(VERIFY_READ, from, n) ?
- __do_copy_from_user(to, from, n,
- &current->thread.fault_addr,
- &current->thread.fault_catcher) : n);
-}
-
-static inline int copy_to_user_tt(void *to, const void *from, int n)
-{
- return(access_ok_tt(VERIFY_WRITE, to, n) ?
- __do_copy_to_user(to, from, n,
- &current->thread.fault_addr,
- &current->thread.fault_catcher) : n);
-}
-
extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
void **fault_addr, void **fault_catcher);
-
-static inline int strncpy_from_user_tt(char *dst, const char *src, int count)
-{
- int n;
-
- if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT);
- n = __do_strncpy_from_user(dst, src, count,
- &current->thread.fault_addr,
- &current->thread.fault_catcher);
- if(n < 0) return(-EFAULT);
- return(n);
-}
-
extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
void **fault_catcher);
-
-static inline int __clear_user_tt(void *mem, int len)
-{
- return(__do_clear_user(mem, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
-
-static inline int clear_user_tt(void *mem, int len)
-{
- return(access_ok_tt(VERIFY_WRITE, mem, len) ?
- __do_clear_user(mem, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher) : len);
-}
-
extern int __do_strnlen_user(const char *str, unsigned long n,
void **fault_addr, void **fault_catcher);
-static inline int strnlen_user_tt(const void *str, int len)
-{
- return(__do_strnlen_user(str, len,
- &current->thread.fault_addr,
- &current->thread.fault_catcher));
-}
+extern int copy_from_user_tt(void *to, const void *from, int n);
+extern int copy_to_user_tt(void *to, const void *from, int n);
+extern int strncpy_from_user_tt(char *dst, const char *src, int count);
+extern int __clear_user_tt(void *mem, int len);
+extern int clear_user_tt(void *mem, int len);
+extern int strnlen_user_tt(const void *str, int len);
#endif
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
index 0c39b26638899..34090b8d29836 100644
--- a/arch/um/kernel/tt/mem.c
+++ b/arch/um/kernel/tt/mem.c
@@ -18,7 +18,7 @@ void before_mem_tt(unsigned long brk_start)
if(!jail || debug)
remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
- remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(brk_start), 1);
+ remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
}
#ifdef CONFIG_HOST_2G_2G
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
index e10db3f1fccd8..3085267459b16 100644
--- a/arch/um/kernel/tt/mem_user.c
+++ b/arch/um/kernel/tt/mem_user.c
@@ -25,14 +25,13 @@ void remap_data(void *segment_start, void *segment_end, int w)
size = (unsigned long) segment_end -
(unsigned long) segment_start;
data = create_mem_file(size);
- if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ,
- MAP_SHARED, data, 0)) == MAP_FAILED){
+ addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
+ if(addr == MAP_FAILED){
perror("mapping new data segment");
exit(1);
}
memcpy(addr, segment_start, size);
- if(switcheroo(data, prot, addr, segment_start,
- size) < 0){
+ if(switcheroo(data, prot, addr, segment_start, size) < 0){
printf("switcheroo failed\n");
exit(1);
}
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 7a2f330a35331..4b4a1a1ab430b 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -62,7 +62,7 @@ void *switch_to_tt(void *prev, void *next, void *last)
reading = 0;
err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
if(err != sizeof(c))
- panic("write of switch_pipe failed, errno = %d", -err);
+ panic("write of switch_pipe failed, err = %d", -err);
reading = 1;
if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD))
@@ -104,48 +104,72 @@ void *switch_to_tt(void *prev, void *next, void *last)
void release_thread_tt(struct task_struct *task)
{
- os_kill_process(task->thread.mode.tt.extern_pid, 0);
+ int pid = task->thread.mode.tt.extern_pid;
+
+ if(os_getpid() != pid)
+ os_kill_process(pid, 0);
}
void exit_thread_tt(void)
{
- close(current->thread.mode.tt.switch_pipe[0]);
- close(current->thread.mode.tt.switch_pipe[1]);
+ os_close_file(current->thread.mode.tt.switch_pipe[0]);
+ os_close_file(current->thread.mode.tt.switch_pipe[1]);
}
void schedule_tail(task_t *prev);
static void new_thread_handler(int sig)
{
+ unsigned long disable;
int (*fn)(void *);
void *arg;
fn = current->thread.request.u.thread.proc;
arg = current->thread.request.u.thread.arg;
+
UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+ disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
+ (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
+ SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
+
suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
- block_signals();
+ force_flush_all();
+ if(current->thread.prev_sched != NULL)
+ schedule_tail(current->thread.prev_sched);
+ current->thread.prev_sched = NULL;
+
init_new_thread_signals(1);
-#ifdef CONFIG_SMP
- schedule_tail(current->thread.prev_sched);
-#endif
enable_timer();
free_page(current->thread.temp_stack);
set_cmdline("(kernel thread)");
- force_flush_all();
- current->thread.prev_sched = NULL;
change_sig(SIGUSR1, 1);
change_sig(SIGVTALRM, 1);
change_sig(SIGPROF, 1);
- unblock_signals();
+ local_irq_enable();
if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
do_exit(0);
}
static int new_thread_proc(void *stack)
{
+ /* local_irq_disable is needed to block out signals until this thread is
+ * properly scheduled. Otherwise, the tracing thread will get mighty
+ * upset about any signals that arrive before that.
+ * This has the complication that it sets the saved signal mask in
+ * the sigcontext to block signals. This gets restored when this
+ * thread (or a descendant, since they get a copy of this sigcontext)
+ * returns to userspace.
+ * So, this is compensated for elsewhere.
+ * XXX There is still a small window until local_irq_disable() actually
+ * finishes where signals are possible - shouldn't be a problem in
+ * practice since SIGIO hasn't been forwarded here yet, and the
+ * local_irq_disable should finish before a SIGVTALRM has time to be
+ * delivered.
+ */
+
+ local_irq_disable();
init_new_thread_stack(stack, new_thread_handler);
os_usr1_process(os_getpid());
return(0);
@@ -156,7 +180,7 @@ static int new_thread_proc(void *stack)
* itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off,
* so it is blocked before it's called. They are re-enabled on sigreturn
* despite the fact that they were blocked when the SIGUSR1 was issued because
- * copy_thread copies the parent's signcontext, including the signal mask
+ * copy_thread copies the parent's sigcontext, including the signal mask
* onto the signal frame.
*/
@@ -165,35 +189,32 @@ void finish_fork_handler(int sig)
UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
-#ifdef CONFIG_SMP
- schedule_tail(NULL);
-#endif
+ force_flush_all();
+ if(current->thread.prev_sched != NULL)
+ schedule_tail(current->thread.prev_sched);
+ current->thread.prev_sched = NULL;
+
enable_timer();
change_sig(SIGVTALRM, 1);
local_irq_enable();
- force_flush_all();
if(current->mm != current->parent->mm)
protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
1, 0, 1);
- task_protections((unsigned long) current->thread_info);
-
- current->thread.prev_sched = NULL;
+ task_protections((unsigned long) current_thread);
free_page(current->thread.temp_stack);
+ local_irq_disable();
change_sig(SIGUSR1, 0);
set_user_mode(current);
}
-static int sigusr1 = SIGUSR1;
-
int fork_tramp(void *stack)
{
- int sig = sigusr1;
-
local_irq_disable();
+ arch_init_thread();
init_new_thread_stack(stack, finish_fork_handler);
- kill(os_getpid(), sig);
+ os_usr1_process(os_getpid());
return(0);
}
@@ -213,8 +234,8 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
}
err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
- if(err){
- printk("copy_thread : pipe failed, errno = %d\n", -err);
+ if(err < 0){
+ printk("copy_thread : pipe failed, err = %d\n", -err);
return(err);
}
@@ -377,8 +398,8 @@ static void mprotect_kernel_mem(int w)
pages = (1 << CONFIG_KERNEL_STACK_ORDER);
- start = (unsigned long) current->thread_info + PAGE_SIZE;
- end = (unsigned long) current + PAGE_SIZE * pages;
+ start = (unsigned long) current_thread + PAGE_SIZE;
+ end = (unsigned long) current_thread + PAGE_SIZE * pages;
protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
protect_memory(end, high_physmem - end, 1, w, 1, 1);
@@ -391,7 +412,7 @@ static void mprotect_kernel_mem(int w)
protect_memory(start, end - start, 1, w, 1, 1);
start = (unsigned long) UML_ROUND_DOWN(&__bss_start);
- end = (unsigned long) UML_ROUND_UP(brk_start);
+ end = (unsigned long) UML_ROUND_UP(&_end);
protect_memory(start, end - start, 1, w, 1, 1);
mprotect_kernel_vm(w);
@@ -454,8 +475,9 @@ void set_init_pid(int pid)
init_task.thread.mode.tt.extern_pid = pid;
err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
- if(err) panic("Can't create switch pipe for init_task, errno = %d",
- err);
+ if(err)
+ panic("Can't create switch pipe for init_task, errno = %d",
+ -err);
}
int singlestepping_tt(void *t)
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
index 97d4f0bc18d7b..9f9daf5c17837 100644
--- a/arch/um/kernel/tt/ptproxy/Makefile
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -9,5 +9,3 @@ USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-clean:
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
index 65504f8c6565c..458ecf9a45f18 100644
--- a/arch/um/kernel/tt/ptproxy/proxy.c
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -15,7 +15,6 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml
#include <unistd.h>
#include <signal.h>
#include <string.h>
-#include <fcntl.h>
#include <termios.h>
#include <sys/wait.h>
#include <sys/types.h>
@@ -273,7 +272,7 @@ void fake_child_exit(void)
child_proxy(1, W_EXITCODE(0, 0));
while(debugger.waiting == 1){
- pid = waitpid(debugger.pid, &status, WUNTRACED);
+ CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
if(pid != debugger.pid){
printk("fake_child_exit - waitpid failed, "
"errno = %d\n", errno);
@@ -281,7 +280,7 @@ void fake_child_exit(void)
}
debugger_proxy(status, debugger.pid);
}
- pid = waitpid(debugger.pid, &status, WUNTRACED);
+ CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
if(pid != debugger.pid){
printk("fake_child_exit - waitpid failed, "
"errno = %d\n", errno);
@@ -293,10 +292,10 @@ void fake_child_exit(void)
}
char gdb_init_string[] =
-"att 1
-b panic
-b stop
-handle SIGWINCH nostop noprint pass
+"att 1 \n\
+b panic \n\
+b stop \n\
+handle SIGWINCH nostop noprint pass \n\
";
int start_debugger(char *prog, int startup, int stop, int *fd_out)
@@ -304,7 +303,8 @@ int start_debugger(char *prog, int startup, int stop, int *fd_out)
int slave, child;
slave = open_gdb_chan();
- if((child = fork()) == 0){
+ child = fork();
+ if(child == 0){
char *tempname = NULL;
int fd;
@@ -327,18 +327,19 @@ int start_debugger(char *prog, int startup, int stop, int *fd_out)
exit(1);
#endif
}
- if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
- printk("start_debugger : make_tempfile failed, errno = %d\n",
- errno);
+ fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
+ if(fd < 0){
+ printk("start_debugger : make_tempfile failed,"
+ "err = %d\n", -fd);
exit(1);
}
- write(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+ os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
if(startup){
if(stop){
- write(fd, "b start_kernel\n",
+ os_write_file(fd, "b start_kernel\n",
strlen("b start_kernel\n"));
}
- write(fd, "c\n", strlen("c\n"));
+ os_write_file(fd, "c\n", strlen("c\n"));
}
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
printk("start_debugger : PTRACE_TRACEME failed, "
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
index 50a120d5e65c0..c42855aeda605 100644
--- a/arch/um/kernel/tt/ptproxy/sysdep.c
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -9,6 +9,7 @@ terms and conditions.
#include <string.h>
#include <stdlib.h>
#include <signal.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <asm/ptrace.h>
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
index aad7e4b62ee5d..86ef67653e726 100644
--- a/arch/um/kernel/tt/ptproxy/wait.c
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -56,21 +56,23 @@ int parent_wait_return(struct debugger *debugger, pid_t unused)
int real_wait_return(struct debugger *debugger)
{
unsigned long ip;
- int err, pid;
+ int pid;
pid = debugger->pid;
+
ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
- ip = IP_RESTART_SYSCALL(ip);
- err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip);
+ IP_RESTART_SYSCALL(ip);
+
if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
tracer_panic("real_wait_return : Failed to restart system "
- "call, errno = %d\n");
+ "call, errno = %d\n", errno);
+
if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
debugger_normal_return(debugger, -1))
tracer_panic("real_wait_return : gdb failed to wait, "
- "errno = %d\n");
+ "errno = %d\n", errno);
return(0);
}
diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile
index 2ad8271c604d5..3eeea057c591d 100644
--- a/arch/um/kernel/tt/sys-i386/Makefile
+++ b/arch/um/kernel/tt/sys-i386/Makefile
@@ -10,5 +10,3 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-clean :
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
index 1b71f9ce51843..555ffd0ee3478 100644
--- a/arch/um/kernel/tt/syscall_kern.c
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
index f7c845d997554..1cabbd8669011 100644
--- a/arch/um/kernel/tt/syscall_user.c
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -33,7 +33,7 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs)
SC_START_SYSCALL(sc);
index = record_syscall_start(syscall);
- syscall_trace();
+ syscall_trace(regs, 1);
result = execute_syscall(regs);
/* regs->sc may have changed while the system call ran (there may
@@ -46,7 +46,7 @@ void syscall_handler_tt(int sig, union uml_pt_regs *regs)
(result == -ERESTARTNOINTR))
do_signal(result);
- syscall_trace();
+ syscall_trace(regs, 0);
record_syscall_end(index, result);
}
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 32ac316de2afd..d8ad334cfac93 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -10,6 +10,7 @@
#include "asm/page.h"
#include "asm/pgtable.h"
#include "asm/uaccess.h"
+#include "asm/tlbflush.h"
#include "user_util.h"
#include "mem_user.h"
#include "os.h"
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
index 6a6322a3e0bc3..1b547741244a0 100644
--- a/arch/um/kernel/tt/tracer.c
+++ b/arch/um/kernel/tt/tracer.c
@@ -39,16 +39,17 @@ int is_tracer_winch(int pid, int fd, void *data)
return(0);
register_winch_irq(tracer_winch[0], fd, -1, data);
- return(0);
+ return(1);
}
static void tracer_winch_handler(int sig)
{
+ int n;
char c = 1;
- if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
- printk("tracer_winch_handler - write failed, errno = %d\n",
- errno);
+ n = os_write_file(tracer_winch[1], &c, sizeof(c));
+ if(n != sizeof(c))
+ printk("tracer_winch_handler - write failed, err = %d\n", -n);
}
/* Called only by the tracing thread during initialization */
@@ -58,9 +59,8 @@ static void setup_tracer_winch(void)
int err;
err = os_pipe(tracer_winch, 1, 1);
- if(err){
- printk("setup_tracer_winch : os_pipe failed, errno = %d\n",
- -err);
+ if(err < 0){
+ printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
return;
}
signal(SIGWINCH, tracer_winch_handler);
@@ -130,8 +130,8 @@ static void sleeping_process_signal(int pid, int sig)
case SIGTSTP:
if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
tracer_panic("sleeping_process_signal : Failed to "
- "continue pid %d, errno = %d\n", pid,
- sig);
+ "continue pid %d, signal = %d, "
+ "errno = %d\n", pid, sig, errno);
break;
/* This happens when the debugger (e.g. strace) is doing system call
@@ -145,7 +145,7 @@ static void sleeping_process_signal(int pid, int sig)
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
tracer_panic("sleeping_process_signal : Failed to "
"PTRACE_SYSCALL pid %d, errno = %d\n",
- pid, sig);
+ pid, errno);
break;
case SIGSTOP:
break;
@@ -192,7 +192,7 @@ int tracer(int (*init_proc)(void *), void *sp)
printf("tracing thread pid = %d\n", tracing_pid);
pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0){
printf("waitpid on idle thread failed, errno = %d\n", errno);
exit(1);
@@ -218,7 +218,7 @@ int tracer(int (*init_proc)(void *), void *sp)
err = attach(debugger_parent);
if(err){
printf("Failed to attach debugger parent %d, "
- "errno = %d\n", debugger_parent, err);
+ "errno = %d\n", debugger_parent, -err);
debugger_parent = -1;
}
else {
@@ -233,7 +233,8 @@ int tracer(int (*init_proc)(void *), void *sp)
}
set_cmdline("(tracing thread)");
while(1){
- if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
+ CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
+ if(pid <= 0){
if(errno != ECHILD){
printf("wait failed - errno = %d\n", errno);
}
@@ -401,7 +402,7 @@ static int __init uml_debug_setup(char *line, int *add)
if(!strcmp(line, "go")) debug_stop = 0;
else if(!strcmp(line, "parent")) debug_parent = 1;
- else printk("Unknown debug option : '%s'\n", line);
+ else printf("Unknown debug option : '%s'\n", line);
line = next;
}
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
new file mode 100644
index 0000000000000..0409718935f71
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/uaccess.h"
+
+int copy_from_user_tt(void *to, const void *from, int n)
+{
+ if(!access_ok_tt(VERIFY_READ, from, n))
+ return(n);
+
+ return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+int copy_to_user_tt(void *to, const void *from, int n)
+{
+ if(!access_ok_tt(VERIFY_WRITE, to, n))
+ return(n);
+
+ return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+int strncpy_from_user_tt(char *dst, const char *src, int count)
+{
+ int n;
+
+ if(!access_ok_tt(VERIFY_READ, src, 1))
+ return(-EFAULT);
+
+ n = __do_strncpy_from_user(dst, src, count,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher);
+ if(n < 0) return(-EFAULT);
+ return(n);
+}
+
+int __clear_user_tt(void *mem, int len)
+{
+ return(__do_clear_user(mem, len,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+int clear_user_tt(void *mem, int len)
+{
+ if(!access_ok_tt(VERIFY_WRITE, mem, len))
+ return(len);
+
+ return(__do_clear_user(mem, len, &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+int strnlen_user_tt(const void *str, int len)
+{
+ return(__do_strnlen_user(str, len,
+ &current->thread.fault_addr,
+ &current->thread.fault_catcher));
+}
+
+/*
+ * 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/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
index 537ee9fba4032..f084f0c2bd914 100644
--- a/arch/um/kernel/tt/uaccess_user.c
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -8,15 +8,20 @@
#include <string.h>
#include "user_util.h"
#include "uml_uaccess.h"
+#include "task.h"
+#include "kern_util.h"
int __do_copy_from_user(void *to, const void *from, int n,
void **fault_addr, void **fault_catcher)
{
+ struct tt_regs save = TASK_REGS(get_current())->tt;
unsigned long fault;
int faulted;
fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
__do_copy, &faulted);
+ TASK_REGS(get_current())->tt = save;
+
if(!faulted) return(0);
else return(n - (fault - (unsigned long) from));
}
@@ -29,11 +34,14 @@ static void __do_strncpy(void *dst, const void *src, int count)
int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
void **fault_addr, void **fault_catcher)
{
+ struct tt_regs save = TASK_REGS(get_current())->tt;
unsigned long fault;
int faulted;
fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
__do_strncpy, &faulted);
+ TASK_REGS(get_current())->tt = save;
+
if(!faulted) return(strlen(dst));
else return(-1);
}
@@ -46,11 +54,14 @@ static void __do_clear(void *to, const void *from, int n)
int __do_clear_user(void *mem, unsigned long len,
void **fault_addr, void **fault_catcher)
{
+ struct tt_regs save = TASK_REGS(get_current())->tt;
unsigned long fault;
int faulted;
fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
__do_clear, &faulted);
+ TASK_REGS(get_current())->tt = save;
+
if(!faulted) return(0);
else return(len - (fault - (unsigned long) mem));
}
@@ -58,19 +69,20 @@ int __do_clear_user(void *mem, unsigned long len,
int __do_strnlen_user(const char *str, unsigned long n,
void **fault_addr, void **fault_catcher)
{
+ struct tt_regs save = TASK_REGS(get_current())->tt;
int ret;
unsigned long *faddrp = (unsigned long *)fault_addr;
jmp_buf jbuf;
*fault_catcher = &jbuf;
- if(setjmp(jbuf) == 0){
+ if(sigsetjmp(jbuf, 1) == 0)
ret = strlen(str) + 1;
- }
- else {
- ret = *faddrp - (unsigned long) str;
- }
+ else ret = *faddrp - (unsigned long) str;
+
*fault_addr = NULL;
*fault_catcher = NULL;
+
+ TASK_REGS(get_current())->tt = save;
return ret;
}
diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c
index 36d3e69929c3d..3f7aecdbe5328 100644
--- a/arch/um/kernel/tt/unmap.c
+++ b/arch/um/kernel/tt/unmap.c
@@ -3,10 +3,7 @@
* Licensed under the GPL
*/
-#include <stdio.h>
-#include <errno.h>
#include <sys/mman.h>
-#include "user.h"
int switcheroo(int fd, int prot, void *from, void *to, int size)
{
diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
index 61c4cc3af749c..0a70c5e663c06 100644
--- a/arch/um/kernel/tty_log.c
+++ b/arch/um/kernel/tty_log.c
@@ -9,10 +9,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#include <sys/time.h>
#include "init.h"
#include "user.h"
+#include "kern_util.h"
#include "os.h"
#define TTY_LOG_DIR "./"
@@ -24,29 +24,40 @@ static int tty_log_fd = -1;
#define TTY_LOG_OPEN 1
#define TTY_LOG_CLOSE 2
#define TTY_LOG_WRITE 3
+#define TTY_LOG_EXEC 4
+
+#define TTY_READ 1
+#define TTY_WRITE 2
struct tty_log_buf {
int what;
unsigned long tty;
int len;
+ int direction;
+ unsigned long sec;
+ unsigned long usec;
};
-int open_tty_log(void *tty)
+int open_tty_log(void *tty, void *current_tty)
{
struct timeval tv;
struct tty_log_buf data;
char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
int fd;
+ gettimeofday(&tv, NULL);
if(tty_log_fd != -1){
- data = ((struct tty_log_buf) { what : TTY_LOG_OPEN,
- tty : (unsigned long) tty,
- len : 0 });
- write(tty_log_fd, &data, sizeof(data));
+ data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN,
+ .tty = (unsigned long) tty,
+ .len = sizeof(current_tty),
+ .direction = 0,
+ .sec = tv.tv_sec,
+ .usec = tv.tv_usec } );
+ os_write_file(tty_log_fd, &data, sizeof(data));
+ os_write_file(tty_log_fd, &current_tty, data.len);
return(tty_log_fd);
}
- gettimeofday(&tv, NULL);
sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
(unsigned int) tv.tv_usec);
@@ -62,30 +73,117 @@ int open_tty_log(void *tty)
void close_tty_log(int fd, void *tty)
{
struct tty_log_buf data;
+ struct timeval tv;
if(tty_log_fd != -1){
- data = ((struct tty_log_buf) { what : TTY_LOG_CLOSE,
- tty : (unsigned long) tty,
- len : 0 });
- write(tty_log_fd, &data, sizeof(data));
+ gettimeofday(&tv, NULL);
+ data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE,
+ .tty = (unsigned long) tty,
+ .len = 0,
+ .direction = 0,
+ .sec = tv.tv_sec,
+ .usec = tv.tv_usec } );
+ os_write_file(tty_log_fd, &data, sizeof(data));
return;
}
- close(fd);
+ os_close_file(fd);
}
-int write_tty_log(int fd, char *buf, int len, void *tty)
+static int log_chunk(int fd, const char *buf, int len)
{
+ int total = 0, try, missed, n;
+ char chunk[64];
+
+ while(len > 0){
+ try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
+ missed = copy_from_user_proc(chunk, (char *) buf, try);
+ try -= missed;
+ n = os_write_file(fd, chunk, try);
+ if(n != try) {
+ if(n < 0)
+ return(n);
+ return(-EIO);
+ }
+ if(missed != 0)
+ return(-EFAULT);
+
+ len -= try;
+ total += try;
+ buf += try;
+ }
+
+ return(total);
+}
+
+int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
+{
+ struct timeval tv;
struct tty_log_buf data;
+ int direction;
if(fd == tty_log_fd){
- data = ((struct tty_log_buf) { what : TTY_LOG_WRITE,
- tty : (unsigned long) tty,
- len : len });
- write(tty_log_fd, &data, sizeof(data));
+ gettimeofday(&tv, NULL);
+ direction = is_read ? TTY_READ : TTY_WRITE;
+ data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE,
+ .tty = (unsigned long) tty,
+ .len = len,
+ .direction = direction,
+ .sec = tv.tv_sec,
+ .usec = tv.tv_usec } );
+ os_write_file(tty_log_fd, &data, sizeof(data));
}
- return(write(fd, buf, len));
+
+ return(log_chunk(fd, buf, len));
}
+void log_exec(char **argv, void *tty)
+{
+ struct timeval tv;
+ struct tty_log_buf data;
+ char **ptr,*arg;
+ int len;
+
+ if(tty_log_fd == -1) return;
+
+ gettimeofday(&tv, NULL);
+
+ len = 0;
+ for(ptr = argv; ; ptr++){
+ if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
+ return;
+ if(arg == NULL) break;
+ len += strlen_user_proc(arg);
+ }
+
+ data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC,
+ .tty = (unsigned long) tty,
+ .len = len,
+ .direction = 0,
+ .sec = tv.tv_sec,
+ .usec = tv.tv_usec } );
+ os_write_file(tty_log_fd, &data, sizeof(data));
+
+ for(ptr = argv; ; ptr++){
+ if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
+ return;
+ if(arg == NULL) break;
+ log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
+ }
+}
+
+extern void register_tty_logger(int (*opener)(void *, void *),
+ int (*writer)(int, const char *, int,
+ void *, int),
+ void (*closer)(int, void *));
+
+static int register_logger(void)
+{
+ register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
+ return(0);
+}
+
+__uml_initcall(register_logger);
+
static int __init set_tty_log_dir(char *name, int *add)
{
tty_log_dir = name;
@@ -104,7 +202,7 @@ static int __init set_tty_log_fd(char *name, int *add)
tty_log_fd = strtoul(name, &end, 0);
if((*end != '\0') || (end == name)){
- printk("set_tty_log_fd - strtoul failed on '%s'\n", name);
+ printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
tty_log_fd = -1;
}
return 0;
diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c
index eb9be24cebb1f..fc079512a7016 100644
--- a/arch/um/kernel/uaccess_user.c
+++ b/arch/um/kernel/uaccess_user.c
@@ -20,7 +20,7 @@ unsigned long __do_user_copy(void *to, const void *from, int n,
jmp_buf jbuf;
*fault_catcher = &jbuf;
- if(setjmp(jbuf) == 0){
+ if(sigsetjmp(jbuf, 1) == 0){
(*op)(to, from, n);
ret = 0;
*faulted_out = 0;
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index e8f0cacc1f416..a4e57ebf7db92 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -38,13 +38,18 @@
#include "mode_kern.h"
#include "mode.h"
-#define DEFAULT_COMMAND_LINE "root=6200"
+#define DEFAULT_COMMAND_LINE "root=98:0"
struct cpuinfo_um boot_cpu_data = {
.loops_per_jiffy = 0,
.ipi_pipe = { -1, -1 }
};
+/* Placeholder to make UML link until the vsyscall stuff is actually
+ * implemented
+ */
+void *__kernel_vsyscall;
+
unsigned long thread_saved_pc(struct task_struct *task)
{
return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
@@ -53,18 +58,22 @@ unsigned long thread_saved_pc(struct task_struct *task)
static int show_cpuinfo(struct seq_file *m, void *v)
{
- int index;
+ int index = 0;
- index = (struct cpuinfo_um *)v - cpu_data;
#ifdef CONFIG_SMP
+ index = (struct cpuinfo_um *) v - cpu_data;
if (!cpu_online(index))
return 0;
#endif
- seq_printf(m, "bogomips\t: %lu.%02lu\n",
+ seq_printf(m, "processor\t: %d\n", index);
+ seq_printf(m, "vendor_id\t: User Mode Linux\n");
+ seq_printf(m, "model name\t: UML\n");
+ seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
+ seq_printf(m, "host\t\t: %s\n", host_info);
+ seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ)) % 100);
- seq_printf(m, "host\t\t: %s\n", host_info);
return(0);
}
@@ -134,12 +143,12 @@ void set_cmdline(char *cmd)
if(umid != NULL){
snprintf(argv1_begin,
(argv1_end - argv1_begin) * sizeof(*ptr),
- "(%s)", umid);
+ "(%s) ", umid);
ptr = &argv1_begin[strlen(argv1_begin)];
}
else ptr = argv1_begin;
- snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd);
+ snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
memset(argv1_begin + strlen(argv1_begin), '\0',
argv1_end - argv1_begin - strlen(argv1_begin));
#endif
@@ -179,7 +188,7 @@ __uml_setup("root=", uml_root_setup,
static int __init uml_ncpus_setup(char *line, int *add)
{
if (!sscanf(line, "%d", &ncpus)) {
- printk("Couldn't parse [%s]\n", line);
+ printf("Couldn't parse [%s]\n", line);
return -1;
}
@@ -210,7 +219,7 @@ static int __init mode_tt_setup(char *line, int *add)
static int __init mode_tt_setup(char *line, int *add)
{
- printk("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
+ printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
return(0);
}
@@ -221,7 +230,7 @@ static int __init mode_tt_setup(char *line, int *add)
static int __init mode_tt_setup(char *line, int *add)
{
- printk("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
+ printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
return(0);
}
@@ -291,7 +300,7 @@ static void __init uml_postsetup(void)
/* Set during early boot */
unsigned long brk_start;
-static struct vm_reserved kernel_vm_reserved;
+unsigned long end_iomem;
#define MIN_VMALLOC (32 * 1024 * 1024)
@@ -299,7 +308,7 @@ int linux_main(int argc, char **argv)
{
unsigned long avail;
unsigned long virtmem_size, max_physmem;
- unsigned int i, add, err;
+ unsigned int i, add;
for (i = 1; i < argc; i++){
if((i == 1) && (argv[i][0] == ' ')) continue;
@@ -328,12 +337,16 @@ int linux_main(int argc, char **argv)
argv1_end = &argv[1][strlen(argv[1])];
#endif
- set_usable_vm(uml_physmem, get_kmem_end());
-
highmem = 0;
- max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC;
- if(physmem_size > max_physmem){
- highmem = physmem_size - max_physmem;
+ iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
+ max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
+
+ /* Zones have to begin on a 1 << MAX_ORDER page boundary,
+ * so this makes sure that's true for highmem
+ */
+ max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
+ if(physmem_size + iomem_size > max_physmem){
+ highmem = physmem_size + iomem_size - max_physmem;
physmem_size -= highmem;
#ifndef CONFIG_HIGHMEM
highmem = 0;
@@ -343,11 +356,19 @@ int linux_main(int argc, char **argv)
}
high_physmem = uml_physmem + physmem_size;
- high_memory = (void *) high_physmem;
+ end_iomem = high_physmem + iomem_size;
+ high_memory = (void *) end_iomem;
start_vm = VMALLOC_START;
- setup_physmem(uml_physmem, uml_reserved, physmem_size);
+ setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
+ if(init_maps(physmem_size, iomem_size, highmem)){
+ printf("Failed to allocate mem_map for %ld bytes of physical "
+ "memory and %ld bytes of highmem\n", physmem_size,
+ highmem);
+ exit(1);
+ }
+
virtmem_size = physmem_size;
avail = get_kmem_end() - start_vm;
if(physmem_size > avail) virtmem_size = avail;
@@ -357,28 +378,26 @@ int linux_main(int argc, char **argv)
printf("Kernel virtual memory size shrunk to %ld bytes\n",
virtmem_size);
- err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved);
- if(err){
- printf("Failed to reserve VM area for kernel VM\n");
- exit(1);
- }
-
uml_postsetup();
init_task.thread.kernel_stack = (unsigned long) &init_thread_info +
2 * PAGE_SIZE;
task_protections((unsigned long) &init_thread_info);
+ os_flush_stdout();
return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
}
+extern int uml_exitcode;
+
static int panic_exit(struct notifier_block *self, unsigned long unused1,
void *unused2)
{
#ifdef CONFIG_MAGIC_SYSRQ
- handle_sysrq('p', &current->thread.regs, NULL, NULL);
+ handle_sysrq('p', &current->thread.regs, NULL);
#endif
+ uml_exitcode = 1;
machine_halt();
return(0);
}
@@ -403,6 +422,11 @@ void __init check_bugs(void)
arch_check_bugs();
check_ptrace();
check_sigio();
+ check_devanon();
+}
+
+void apply_alternatives(void *start, void *end)
+{
}
/*
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
index 1da1a0d664a81..a03eb1561f195 100644
--- a/arch/um/kernel/umid.c
+++ b/arch/um/kernel/umid.c
@@ -5,7 +5,6 @@
#include <stdio.h>
#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
@@ -33,18 +32,19 @@ static char *uml_dir = UML_DIR;
static int umid_is_random = 1;
static int umid_inited = 0;
-static int make_umid(void);
+static int make_umid(int (*printer)(const char *fmt, ...));
-static int __init set_umid(char *name, int is_random)
+static int __init set_umid(char *name, int is_random,
+ int (*printer)(const char *fmt, ...))
{
if(umid_inited){
- printk("Unique machine name can't be set twice\n");
+ (*printer)("Unique machine name can't be set twice\n");
return(-1);
}
if(strlen(name) > UMID_LEN - 1)
- printk("Unique machine name is being truncated to %s "
- "characters\n", UMID_LEN);
+ (*printer)("Unique machine name is being truncated to %s "
+ "characters\n", UMID_LEN);
strlcpy(umid, name, sizeof(umid));
umid_is_random = is_random;
@@ -54,7 +54,7 @@ static int __init set_umid(char *name, int is_random)
static int __init set_umid_arg(char *name, int *add)
{
- return(set_umid(name, 0));
+ return(set_umid(name, 0, printf));
}
__uml_setup("umid=", set_umid_arg,
@@ -67,7 +67,7 @@ int __init umid_file_name(char *name, char *buf, int len)
{
int n;
- if(!umid_inited && make_umid()) return(-1);
+ if(!umid_inited && make_umid(printk)) return(-1);
n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
if(n > len){
@@ -85,22 +85,23 @@ static int __init create_pid_file(void)
{
char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
char pid[sizeof("nnnnn\0")];
- int fd;
+ int fd, n;
if(umid_file_name("pid", file, sizeof(file))) return 0;
fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
0644);
if(fd < 0){
- printk("Open of machine pid file \"%s\" failed - "
- "errno = %d\n", file, -fd);
+ printf("Open of machine pid file \"%s\" failed - "
+ "err = %d\n", file, -fd);
return 0;
}
sprintf(pid, "%d\n", os_getpid());
- if(write(fd, pid, strlen(pid)) != strlen(pid))
- printk("Write of pid file failed - errno = %d\n", errno);
- close(fd);
+ n = os_write_file(fd, pid, strlen(pid));
+ if(n != strlen(pid))
+ printf("Write of pid file failed - err = %d\n", -n);
+ os_close_file(fd);
return 0;
}
@@ -111,7 +112,8 @@ static int actually_do_remove(char *dir)
int len;
char file[256];
- if((directory = opendir(dir)) == NULL){
+ directory = opendir(dir);
+ if(directory == NULL){
printk("actually_do_remove : couldn't open directory '%s', "
"errno = %d\n", dir, errno);
return(1);
@@ -160,22 +162,24 @@ int not_dead_yet(char *dir)
{
char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
char pid[sizeof("nnnnn\0")], *end;
- int dead, fd, p;
+ int dead, fd, p, n;
sprintf(file, "%s/pid", dir);
dead = 0;
- if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){
+ fd = os_open_file(file, of_read(OPENFLAGS()), 0);
+ if(fd < 0){
if(fd != -ENOENT){
printk("not_dead_yet : couldn't open pid file '%s', "
- "errno = %d\n", file, -fd);
+ "err = %d\n", file, -fd);
return(1);
}
dead = 1;
}
if(fd > 0){
- if(read(fd, pid, sizeof(pid)) < 0){
+ n = os_read_file(fd, pid, sizeof(pid));
+ if(n < 0){
printk("not_dead_yet : couldn't read pid file '%s', "
- "errno = %d\n", file, errno);
+ "err = %d\n", file, -n);
return(1);
}
p = strtoul(pid, &end, 0);
@@ -197,7 +201,7 @@ static int __init set_uml_dir(char *name, int *add)
if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
uml_dir = malloc(strlen(name) + 1);
if(uml_dir == NULL){
- printk("Failed to malloc uml_dir - error = %d\n",
+ printf("Failed to malloc uml_dir - error = %d\n",
errno);
uml_dir = name;
return(0);
@@ -217,7 +221,7 @@ static int __init make_uml_dir(void)
char *home = getenv("HOME");
if(home == NULL){
- printk("make_uml_dir : no value in environment for "
+ printf("make_uml_dir : no value in environment for "
"$HOME\n");
exit(1);
}
@@ -232,57 +236,59 @@ static int __init make_uml_dir(void)
dir[len + 1] = '\0';
}
- if((uml_dir = malloc(strlen(dir) + 1)) == NULL){
+ uml_dir = malloc(strlen(dir) + 1);
+ if(uml_dir == NULL){
printf("make_uml_dir : malloc failed, errno = %d\n", errno);
exit(1);
}
strcpy(uml_dir, dir);
if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
- printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
+ printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
return(-1);
}
return 0;
}
-static int __init make_umid(void)
+static int __init make_umid(int (*printer)(const char *fmt, ...))
{
int fd, err;
char tmp[strlen(uml_dir) + UMID_LEN + 1];
strlcpy(tmp, uml_dir, sizeof(tmp));
- if(*umid == 0){
+ if(!umid_inited){
strcat(tmp, "XXXXXX");
fd = mkstemp(tmp);
if(fd < 0){
- printk("make_umid - mkstemp failed, errno = %d\n",
- errno);
+ (*printer)("make_umid - mkstemp failed, errno = %d\n",
+ errno);
return(1);
}
- close(fd);
+ os_close_file(fd);
/* There's a nice tiny little race between this unlink and
* the mkdir below. It'd be nice if there were a mkstemp
* for directories.
*/
unlink(tmp);
- set_umid(&tmp[strlen(uml_dir)], 1);
+ set_umid(&tmp[strlen(uml_dir)], 1, printer);
}
sprintf(tmp, "%s%s", uml_dir, umid);
- if((err = mkdir(tmp, 0777)) < 0){
+ err = mkdir(tmp, 0777);
+ if(err < 0){
if(errno == EEXIST){
if(not_dead_yet(tmp)){
- printk("umid '%s' is in use\n", umid);
+ (*printer)("umid '%s' is in use\n", umid);
return(-1);
}
err = mkdir(tmp, 0777);
}
}
if(err < 0){
- printk("Failed to create %s - errno = %d\n", umid, errno);
+ (*printer)("Failed to create %s - errno = %d\n", umid, errno);
return(-1);
}
@@ -295,7 +301,13 @@ __uml_setup("uml_dir=", set_uml_dir,
);
__uml_postsetup(make_uml_dir);
-__uml_postsetup(make_umid);
+
+static int __init make_umid_setup(void)
+{
+ return(make_umid(printf));
+}
+
+__uml_postsetup(make_umid_setup);
__uml_postsetup(create_pid_file);
/*
diff --git a/arch/um/uml.lds.S b/arch/um/kernel/uml.lds.S
index d182fb5de99bf..89ed32983dd59 100644
--- a/arch/um/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -1,5 +1,5 @@
#include <asm-generic/vmlinux.lds.h>
-
+
OUTPUT_FORMAT(ELF_FORMAT)
OUTPUT_ARCH(ELF_ARCH)
ENTRY(_start)
@@ -9,7 +9,6 @@ SECTIONS
{
. = START + SIZEOF_HEADERS;
- . = ALIGN(4096);
__binary_start = .;
#ifdef MODE_TT
.thread_private : {
@@ -26,11 +25,16 @@ SECTIONS
. = ALIGN(4096); /* Init code and data */
_stext = .;
__init_begin = .;
- .text.init : { *(.text.init) }
+ .init.text : {
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
. = ALIGN(4096);
.text :
{
*(.text)
+ SCHED_TEXT
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
@@ -38,7 +42,7 @@ SECTIONS
#include "asm/common.lds.S"
- .data.init : { *(.data.init) }
+ init.data : { *(init.data) }
.data :
{
. = ALIGN(KERNEL_STACK_SIZE); /* init_task */
@@ -66,12 +70,12 @@ SECTIONS
_edata = .;
PROVIDE (edata = .);
. = ALIGN(0x1000);
- .sbss :
+ .sbss :
{
__bss_start = .;
PROVIDE(_bss_start = .);
- *(.sbss)
- *(.scommon)
+ *(.sbss)
+ *(.scommon)
}
.bss :
{
diff --git a/arch/um/kernel/user_syms.c b/arch/um/kernel/user_syms.c
deleted file mode 100644
index 2d32ea3c50afe..0000000000000
--- a/arch/um/kernel/user_syms.c
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <utime.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/vfs.h>
-#include <sys/ioctl.h>
-#include "user_util.h"
-#include "mem_user.h"
-#include "uml-config.h"
-
-/* Had to steal this from linux/module.h because that file can't be included
- * since this includes various user-level headers.
- */
-
-struct module_symbol
-{
- unsigned long value;
- const char *name;
-};
-
-/* Indirect stringification. */
-
-#define __MODULE_STRING_1(x) #x
-#define __MODULE_STRING(x) __MODULE_STRING_1(x)
-
-#if !defined(__AUTOCONF_INCLUDED__)
-
-#define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module
-#define EXPORT_SYMBOL(var) error config_must_be_included_before_module
-#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module
-
-#elif !defined(UML_CONFIG_MODULES)
-
-#define __EXPORT_SYMBOL(sym,str)
-#define EXPORT_SYMBOL(var)
-#define EXPORT_SYMBOL_NOVERS(var)
-
-#else
-
-#define __EXPORT_SYMBOL(sym, str) \
-const char __kstrtab_##sym[] \
-__attribute__((section(".kstrtab"))) = str; \
-const struct module_symbol __ksymtab_##sym \
-__attribute__((section("__ksymtab"))) = \
-{ (unsigned long)&sym, __kstrtab_##sym }
-
-#if defined(__MODVERSIONS__) || !defined(UML_CONFIG_MODVERSIONS)
-#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var))
-#else
-#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
-#endif
-
-#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var))
-
-#endif
-
-EXPORT_SYMBOL(__errno_location);
-
-EXPORT_SYMBOL(access);
-EXPORT_SYMBOL(open);
-EXPORT_SYMBOL(open64);
-EXPORT_SYMBOL(close);
-EXPORT_SYMBOL(read);
-EXPORT_SYMBOL(write);
-EXPORT_SYMBOL(dup2);
-EXPORT_SYMBOL(__xstat);
-EXPORT_SYMBOL(__lxstat);
-EXPORT_SYMBOL(__lxstat64);
-EXPORT_SYMBOL(lseek);
-EXPORT_SYMBOL(lseek64);
-EXPORT_SYMBOL(chown);
-EXPORT_SYMBOL(truncate);
-EXPORT_SYMBOL(utime);
-EXPORT_SYMBOL(chmod);
-EXPORT_SYMBOL(rename);
-EXPORT_SYMBOL(__xmknod);
-
-EXPORT_SYMBOL(symlink);
-EXPORT_SYMBOL(link);
-EXPORT_SYMBOL(unlink);
-EXPORT_SYMBOL(readlink);
-
-EXPORT_SYMBOL(mkdir);
-EXPORT_SYMBOL(rmdir);
-EXPORT_SYMBOL(opendir);
-EXPORT_SYMBOL(readdir);
-EXPORT_SYMBOL(closedir);
-EXPORT_SYMBOL(seekdir);
-EXPORT_SYMBOL(telldir);
-
-EXPORT_SYMBOL(ioctl);
-
-extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes,
- __off64_t __offset);
-extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n,
- __off64_t __offset);
-EXPORT_SYMBOL(pread64);
-EXPORT_SYMBOL(pwrite64);
-
-EXPORT_SYMBOL(statfs);
-EXPORT_SYMBOL(statfs64);
-
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(getuid);
-
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(strstr);
-
-EXPORT_SYMBOL(find_iomem);
diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
index 9e4fbae936178..544ae54ce77d9 100644
--- a/arch/um/kernel/user_util.c
+++ b/arch/um/kernel/user_util.c
@@ -5,7 +5,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/mman.h>
@@ -81,10 +80,10 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay)
int status, ret;
while(1){
- if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) ||
+ CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
+ if((ret < 0) ||
!WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
if(ret < 0){
- if(errno == EINTR) continue;
printk("wait failed, errno = %d\n",
errno);
}
@@ -118,29 +117,36 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay)
}
}
-int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags)
-{
- int pid;
-
- pid = clone(fn, sp, flags, arg);
- if(pid < 0) return(-1);
- wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
- ptrace(PTRACE_CONT, pid, 0, 0);
- return(pid);
-}
-
-int raw(int fd, int complain)
+int __raw(int fd, int complain, int now)
{
struct termios tt;
int err;
+ int when;
+
+ CATCH_EINTR(err = tcgetattr(fd, &tt));
+
+ if (err < 0) {
+ if (complain)
+ printk("tcgetattr failed, errno = %d\n", errno);
+ return(-errno);
+ }
- tcgetattr(fd, &tt);
cfmakeraw(&tt);
- err = tcsetattr(fd, TCSANOW, &tt);
- if((err < 0) && complain){
- printk("tcsetattr failed, errno = %d\n", errno);
+
+ if (now)
+ when = TCSANOW;
+ else
+ when = TCSADRAIN;
+
+ CATCH_EINTR(err = tcsetattr(fd, when, &tt));
+
+ if (err < 0) {
+ if (complain)
+ printk("tcsetattr failed, errno = %d\n", errno);
return(-errno);
}
+ /*XXX: tcsetattr could have applied only some changes
+ * (and cfmakeraw() is a set of changes) */
return(0);
}
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 37eea4a327a28..4fa03137aa831 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -3,13 +3,9 @@
# Licensed under the GPL
#
-obj-y = file.o process.o tty.o drivers/
+obj-y = file.o process.o tty.o user_syms.o drivers/
USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
-
-clean :
-
-archmrproper:
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
index 17f15610400de..6ae4b19d9f50e 100644
--- a/arch/um/os-Linux/drivers/ethertap_kern.c
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -8,7 +8,6 @@
#include "linux/init.h"
#include "linux/netdevice.h"
#include "linux/etherdevice.h"
-#include "linux/init.h"
#include "net_kern.h"
#include "net_user.h"
#include "etap.h"
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index e27592985f926..cd4d6544da715 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -8,7 +8,6 @@
#include <stdio.h>
#include <unistd.h>
#include <stddef.h>
-#include <fcntl.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <sys/socket.h>
@@ -17,6 +16,7 @@
#include <net/if.h>
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "net_user.h"
#include "etap.h"
#include "helper.h"
@@ -42,13 +42,14 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
{
struct addr_change change;
void *output;
+ int n;
change.what = op;
memcpy(change.addr, addr, sizeof(change.addr));
memcpy(change.netmask, netmask, sizeof(change.netmask));
- if(write(fd, &change, sizeof(change)) != sizeof(change))
- printk("etap_change - request failed, errno = %d\n",
- errno);
+ n = os_write_file(fd, &change, sizeof(change));
+ if(n != sizeof(change))
+ printk("etap_change - request failed, err = %d\n", -n);
output = um_kmalloc(page_size());
if(output == NULL)
printk("etap_change : Failed to allocate output buffer\n");
@@ -82,15 +83,15 @@ static void etap_pre_exec(void *arg)
struct etap_pre_exec_data *data = arg;
dup2(data->control_remote, 1);
- close(data->data_me);
- close(data->control_me);
+ os_close_file(data->data_me);
+ os_close_file(data->control_me);
}
static int etap_tramp(char *dev, char *gate, int control_me,
int control_remote, int data_me, int data_remote)
{
struct etap_pre_exec_data pe_data;
- int pid, status, err;
+ int pid, status, err, n;
char version_buf[sizeof("nnnnn\0")];
char data_fd_buf[sizeof("nnnnnn\0")];
char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
@@ -114,21 +115,22 @@ static int etap_tramp(char *dev, char *gate, int control_me,
pe_data.data_me = data_me;
pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
- if(pid < 0) err = errno;
- close(data_remote);
- close(control_remote);
- if(read(control_me, &c, sizeof(c)) != sizeof(c)){
- printk("etap_tramp : read of status failed, errno = %d\n",
- errno);
- return(EINVAL);
+ if(pid < 0) err = pid;
+ os_close_file(data_remote);
+ os_close_file(control_remote);
+ n = os_read_file(control_me, &c, sizeof(c));
+ if(n != sizeof(c)){
+ printk("etap_tramp : read of status failed, err = %d\n", -n);
+ return(-EINVAL);
}
if(c != 1){
printk("etap_tramp : uml_net failed\n");
- err = EINVAL;
- if(waitpid(pid, &status, 0) < 0) err = errno;
- else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){
+ err = -EINVAL;
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
+ if(n < 0)
+ err = -errno;
+ else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
printk("uml_net didn't exit with status 1\n");
- }
}
return(err);
}
@@ -143,14 +145,14 @@ static int etap_open(void *data)
if(err) return(err);
err = os_pipe(data_fds, 0, 0);
- if(err){
- printk("data os_pipe failed - errno = %d\n", -err);
+ if(err < 0){
+ printk("data os_pipe failed - err = %d\n", -err);
return(err);
}
err = os_pipe(control_fds, 1, 0);
- if(err){
- printk("control os_pipe failed - errno = %d\n", -err);
+ if(err < 0){
+ printk("control os_pipe failed - err = %d\n", -err);
return(err);
}
@@ -167,9 +169,9 @@ static int etap_open(void *data)
kfree(output);
}
- if(err != 0){
- printk("etap_tramp failed - errno = %d\n", err);
- return(-err);
+ if(err < 0){
+ printk("etap_tramp failed - err = %d\n", -err);
+ return(err);
}
pri->data_fd = data_fds[0];
@@ -183,11 +185,11 @@ static void etap_close(int fd, void *data)
struct ethertap_data *pri = data;
iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
- close(fd);
+ os_close_file(fd);
os_shutdown_socket(pri->data_fd, 1, 1);
- close(pri->data_fd);
+ os_close_file(pri->data_fd);
pri->data_fd = -1;
- close(pri->control_fd);
+ os_close_file(pri->control_fd);
pri->control_fd = -1;
}
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index c858f1160c1db..4b83c6c3f48d2 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -8,7 +8,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
-#include <fcntl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -19,6 +18,7 @@
#include "net_user.h"
#include "tuntap.h"
#include "kern_util.h"
+#include "user_util.h"
#include "user.h"
#include "helper.h"
#include "os.h"
@@ -61,7 +61,7 @@ static void tuntap_pre_exec(void *arg)
struct tuntap_pre_exec_data *data = arg;
dup2(data->stdout, 1);
- close(data->close_me);
+ os_close_file(data->close_me);
}
static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
@@ -86,7 +86,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
if(pid < 0) return(-pid);
- close(remote);
+ os_close_file(remote);
msg.msg_name = NULL;
msg.msg_namelen = 0;
@@ -107,19 +107,19 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
if(n < 0){
printk("tuntap_open_tramp : recvmsg failed - errno = %d\n",
errno);
- return(errno);
+ return(-errno);
}
- waitpid(pid, NULL, 0);
+ CATCH_EINTR(waitpid(pid, NULL, 0));
cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL){
printk("tuntap_open_tramp : didn't receive a message\n");
- return(EINVAL);
+ return(-EINVAL);
}
if((cmsg->cmsg_level != SOL_SOCKET) ||
(cmsg->cmsg_type != SCM_RIGHTS)){
printk("tuntap_open_tramp : didn't receive a descriptor\n");
- return(EINVAL);
+ return(-EINVAL);
}
*fd_out = ((int *) CMSG_DATA(cmsg))[0];
return(0);
@@ -133,27 +133,29 @@ static int tuntap_open(void *data)
int err, fds[2], len, used;
err = tap_open_common(pri->dev, pri->gate_addr);
- if(err) return(err);
+ if(err < 0)
+ return(err);
if(pri->fixed_config){
- if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){
- printk("Failed to open /dev/net/tun, errno = %d\n",
- errno);
- return(-errno);
+ pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
+ if(pri->fd < 0){
+ printk("Failed to open /dev/net/tun, err = %d\n",
+ -pri->fd);
+ return(pri->fd);
}
memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_flags = IFF_TAP;
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
- printk("TUNSETIFF failed, errno = %d", errno);
- close(pri->fd);
+ printk("TUNSETIFF failed, errno = %d\n", errno);
+ os_close_file(pri->fd);
return(-errno);
}
}
else {
err = os_pipe(fds, 0, 0);
- if(err){
- printk("tuntap_open : os_pipe failed - errno = %d\n",
+ if(err < 0){
+ printk("tuntap_open : os_pipe failed - err = %d\n",
-err);
return(err);
}
@@ -166,19 +168,19 @@ static int tuntap_open(void *data)
fds[1], buffer, len, &used);
output = buffer;
- if(err == 0){
- pri->dev_name = uml_strdup(buffer);
- output += IFNAMSIZ;
- printk(output);
- free_output_buffer(buffer);
- }
- else {
- printk(output);
+ if(err < 0) {
+ printk("%s", output);
free_output_buffer(buffer);
- printk("tuntap_open_tramp failed - errno = %d\n", err);
- return(-err);
+ printk("tuntap_open_tramp failed - err = %d\n", -err);
+ return(err);
}
- close(fds[0]);
+
+ pri->dev_name = uml_strdup(buffer);
+ output += IFNAMSIZ;
+ printk("%s", output);
+ free_output_buffer(buffer);
+
+ os_close_file(fds[0]);
iter_addresses(pri->dev, open_addr, pri->dev_name);
}
@@ -191,7 +193,7 @@ static void tuntap_close(int fd, void *data)
if(!pri->fixed_config)
iter_addresses(pri->dev, close_addr, pri->dev_name);
- close(fd);
+ os_close_file(fd);
pri->fd = -1;
}
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index e622db0075766..957c380785e18 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -8,6 +8,8 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
@@ -17,33 +19,235 @@
#include "user.h"
#include "kern_util.h"
-int os_file_type(char *file)
+static void copy_stat(struct uml_stat *dst, struct stat64 *src)
+{
+ *dst = ((struct uml_stat) {
+ .ust_dev = src->st_dev, /* device */
+ .ust_ino = src->st_ino, /* inode */
+ .ust_mode = src->st_mode, /* protection */
+ .ust_nlink = src->st_nlink, /* number of hard links */
+ .ust_uid = src->st_uid, /* user ID of owner */
+ .ust_gid = src->st_gid, /* group ID of owner */
+ .ust_size = src->st_size, /* total size, in bytes */
+ .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
+ .ust_blocks = src->st_blocks, /* number of blocks allocated */
+ .ust_atime = src->st_atime, /* time of last access */
+ .ust_mtime = src->st_mtime, /* time of last modification */
+ .ust_ctime = src->st_ctime, /* time of last change */
+ });
+}
+
+int os_stat_fd(const int fd, struct uml_stat *ubuf)
+{
+ struct stat64 sbuf;
+ int err;
+
+ do {
+ err = fstat64(fd, &sbuf);
+ } while((err < 0) && (errno == EINTR)) ;
+
+ if(err < 0)
+ return(-errno);
+
+ if(ubuf != NULL)
+ copy_stat(ubuf, &sbuf);
+ return(err);
+}
+
+int os_stat_file(const char *file_name, struct uml_stat *ubuf)
+{
+ struct stat64 sbuf;
+ int err;
+
+ do {
+ err = stat64(file_name, &sbuf);
+ } while((err < 0) && (errno == EINTR)) ;
+
+ if(err < 0)
+ return(-errno);
+
+ if(ubuf != NULL)
+ copy_stat(ubuf, &sbuf);
+ return(err);
+}
+
+int os_access(const char* file, int mode)
+{
+ int amode, err;
+
+ amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
+ (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
+
+ err = access(file, amode);
+ if(err < 0)
+ return(-errno);
+
+ return(0);
+}
+
+void os_print_error(int error, const char* str)
+{
+ errno = error < 0 ? -error : error;
+
+ perror(str);
+}
+
+/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
+int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
+{
+ int err;
+
+ err = ioctl(fd, cmd, arg);
+ if(err < 0)
+ return(-errno);
+
+ return(err);
+}
+
+int os_window_size(int fd, int *rows, int *cols)
+{
+ struct winsize size;
+
+ if(ioctl(fd, TIOCGWINSZ, &size) < 0)
+ return(-errno);
+
+ *rows = size.ws_row;
+ *cols = size.ws_col;
+
+ return(0);
+}
+
+int os_new_tty_pgrp(int fd, int pid)
+{
+ if(ioctl(fd, TIOCSCTTY, 0) < 0){
+ printk("TIOCSCTTY failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ if(tcsetpgrp(fd, pid) < 0){
+ printk("tcsetpgrp failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ return(0);
+}
+
+/* FIXME: ensure namebuf in os_get_if_name is big enough */
+int os_get_ifname(int fd, char* namebuf)
+{
+ if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
+ return(-errno);
+
+ return(0);
+}
+
+int os_set_slip(int fd)
+{
+ int disc, sencap;
+
+ disc = N_SLIP;
+ if(ioctl(fd, TIOCSETD, &disc) < 0){
+ printk("Failed to set slip line discipline - "
+ "errno = %d\n", errno);
+ return(-errno);
+ }
+
+ sencap = 0;
+ if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){
+ printk("Failed to set slip encapsulation - "
+ "errno = %d\n", errno);
+ return(-errno);
+ }
+
+ return(0);
+}
+
+int os_set_owner(int fd, int pid)
+{
+ if(fcntl(fd, F_SETOWN, pid) < 0){
+ int save_errno = errno;
+
+ if(fcntl(fd, F_GETOWN, 0) != pid)
+ return(-save_errno);
+ }
+
+ return(0);
+}
+
+/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */
+int os_sigio_async(int master, int slave)
+{
+ int flags;
+
+ flags = fcntl(master, F_GETFL);
+ if(flags < 0) {
+ printk("fcntl F_GETFL failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+ (fcntl(master, F_SETOWN, os_getpid()) < 0)){
+ printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){
+ printk("fcntl F_SETFL failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
+ return(0);
+}
+
+int os_mode_fd(int fd, int mode)
{
- struct stat64 buf;
+ int err;
+
+ do {
+ err = fchmod(fd, mode);
+ } while((err < 0) && (errno==EINTR)) ;
- if(stat64(file, &buf) == -1)
+ if(err < 0)
return(-errno);
- if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
- else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
- else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
- else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
- else if(S_ISFIFO(buf.st_mode)) return(OS_TYPE_FIFO);
- else if(S_ISSOCK(buf.st_mode)) return(OS_TYPE_SOCK);
+ return(0);
+}
+
+int os_file_type(char *file)
+{
+ struct uml_stat buf;
+ int err;
+
+ err = os_stat_file(file, &buf);
+ if(err < 0)
+ return(err);
+
+ if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR);
+ else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK);
+ else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV);
+ else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV);
+ else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO);
+ else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK);
else return(OS_TYPE_FILE);
}
int os_file_mode(char *file, struct openflags *mode_out)
{
+ int err;
+
*mode_out = OPENFLAGS();
- if(!access(file, W_OK)) *mode_out = of_write(*mode_out);
- else if(errno != EACCES)
- return(-errno);
+ err = os_access(file, OS_ACC_W_OK);
+ if((err < 0) && (err != -EACCES))
+ return(err);
- if(!access(file, R_OK)) *mode_out = of_read(*mode_out);
- else if(errno != EACCES)
- return(-errno);
+ *mode_out = of_write(*mode_out);
+
+ err = os_access(file, OS_ACC_R_OK);
+ if((err < 0) && (err != -EACCES))
+ return(err);
+
+ *mode_out = of_read(*mode_out);
return(0);
}
@@ -63,16 +267,14 @@ int os_open_file(char *file, struct openflags flags, int mode)
if(flags.e) f |= O_EXCL;
fd = open64(file, f, mode);
- if(fd < 0) return(-errno);
-
- if(flags.cl){
- if(fcntl(fd, F_SETFD, 1)){
- close(fd);
- return(-errno);
- }
+ if(fd < 0)
+ return(-errno);
+
+ if(flags.cl && fcntl(fd, F_SETFD, 1)){
+ os_close_file(fd);
+ return(-errno);
}
- return(fd);
return(fd);
}
@@ -90,7 +292,7 @@ int os_connect_socket(char *name)
err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
if(err)
- return(err);
+ return(-errno);
return(fd);
}
@@ -109,88 +311,162 @@ int os_seek_file(int fd, __u64 offset)
return(0);
}
-int os_read_file(int fd, void *buf, int len)
+static int fault_buffer(void *start, int len,
+ int (*copy_proc)(void *addr, void *buf, int len))
{
- int n;
+ int page = getpagesize(), i;
+ char c;
- /* Force buf into memory if it's not already. */
+ for(i = 0; i < len; i += page){
+ if((*copy_proc)(start + i, &c, sizeof(c)))
+ return(-EFAULT);
+ }
+ if((len % page) != 0){
+ if((*copy_proc)(start + len - 1, &c, sizeof(c)))
+ return(-EFAULT);
+ }
+ return(0);
+}
- /* XXX This fails if buf is kernel memory */
-#ifdef notdef
- if(copy_to_user_proc(buf, &c, sizeof(c)))
- return(-EFAULT);
-#endif
+static int file_io(int fd, void *buf, int len,
+ int (*io_proc)(int fd, void *buf, int len),
+ int (*copy_user_proc)(void *addr, void *buf, int len))
+{
+ int n, err;
+
+ do {
+ n = (*io_proc)(fd, buf, len);
+ if((n < 0) && (errno == EFAULT)){
+ err = fault_buffer(buf, len, copy_user_proc);
+ if(err)
+ return(err);
+ n = (*io_proc)(fd, buf, len);
+ }
+ } while((n < 0) && (errno == EINTR));
- n = read(fd, buf, len);
if(n < 0)
return(-errno);
return(n);
}
-int os_write_file(int fd, void *buf, int count)
+int os_read_file(int fd, void *buf, int len)
{
- int n;
-
- /* Force buf into memory if it's not already. */
-
- /* XXX This fails if buf is kernel memory */
-#ifdef notdef
- if(copy_to_user_proc(buf, buf, buf[0]))
- return(-EFAULT);
-#endif
+ return(file_io(fd, buf, len, (int (*)(int, void *, int)) read,
+ copy_from_user_proc));
+}
- n = write(fd, buf, count);
- if(n < 0)
- return(-errno);
- return(n);
+int os_write_file(int fd, const void *buf, int len)
+{
+ return(file_io(fd, (void *) buf, len,
+ (int (*)(int, void *, int)) write, copy_to_user_proc));
}
int os_file_size(char *file, long long *size_out)
{
- struct stat64 buf;
+ struct uml_stat buf;
+ int err;
- if(stat64(file, &buf) == -1){
- printk("Couldn't stat \"%s\" : errno = %d\n", file, errno);
- return(-errno);
+ err = os_stat_file(file, &buf);
+ if(err < 0){
+ printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
+ return(err);
}
- if(S_ISBLK(buf.st_mode)){
+
+ if(S_ISBLK(buf.ust_mode)){
int fd, blocks;
- if((fd = open64(file, O_RDONLY)) < 0){
- printk("Couldn't open \"%s\", errno = %d\n", file,
- errno);
- return(-errno);
+ fd = os_open_file(file, of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open \"%s\", errno = %d\n", file, -fd);
+ return(fd);
}
if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
printk("Couldn't get the block size of \"%s\", "
"errno = %d\n", file, errno);
- close(fd);
- return(-errno);
+ err = -errno;
+ os_close_file(fd);
+ return(err);
}
*size_out = ((long long) blocks) * 512;
- close(fd);
+ os_close_file(fd);
return(0);
}
- *size_out = buf.st_size;
+ *size_out = buf.ust_size;
+ return(0);
+}
+
+int os_file_modtime(char *file, unsigned long *modtime)
+{
+ struct uml_stat buf;
+ int err;
+
+ err = os_stat_file(file, &buf);
+ if(err < 0){
+ printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
+ return(err);
+ }
+
+ *modtime = buf.ust_mtime;
return(0);
}
+int os_get_exec_close(int fd, int* close_on_exec)
+{
+ int ret;
+
+ do {
+ ret = fcntl(fd, F_GETFD);
+ } while((ret < 0) && (errno == EINTR)) ;
+
+ if(ret < 0)
+ return(-errno);
+
+ *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0;
+ return(ret);
+}
+
+int os_set_exec_close(int fd, int close_on_exec)
+{
+ int flag, err;
+
+ if(close_on_exec) flag = FD_CLOEXEC;
+ else flag = 0;
+
+ do {
+ err = fcntl(fd, F_SETFD, flag);
+ } while((err < 0) && (errno == EINTR)) ;
+
+ if(err < 0)
+ return(-errno);
+ return(err);
+}
+
int os_pipe(int *fds, int stream, int close_on_exec)
{
int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
err = socketpair(AF_UNIX, type, 0, fds);
- if(err)
+ if(err < 0)
return(-errno);
if(!close_on_exec)
return(0);
- if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0))
- printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d",
- errno);
+ err = os_set_exec_close(fds[0], 1);
+ if(err < 0)
+ goto error;
+
+ err = os_set_exec_close(fds[1], 1);
+ if(err < 0)
+ goto error;
return(0);
+
+ error:
+ printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
+ os_close_file(fds[1]);
+ os_close_file(fds[0]);
+ return(err);
}
int os_set_fd_async(int fd, int owner)
@@ -270,7 +546,7 @@ int os_shutdown_socket(int fd, int r, int w)
return(-EINVAL);
}
err = shutdown(fd, what);
- if(err)
+ if(err < 0)
return(-errno);
return(0);
}
@@ -315,7 +591,7 @@ int os_rcv_fd(int fd, int *helper_pid_out)
return(new);
}
-int create_unix_socket(char *file, int len)
+int os_create_unix_socket(char *file, int len, int close_on_exec)
{
struct sockaddr_un addr;
int sock, err;
@@ -327,6 +603,13 @@ int create_unix_socket(char *file, int len)
return(-errno);
}
+ if(close_on_exec) {
+ err = os_set_exec_close(sock, 1);
+ if(err < 0)
+ printk("create_unix_socket : close_on_exec failed, "
+ "err = %d", -err);
+ }
+
addr.sun_family = AF_UNIX;
/* XXX Be more careful about overflow */
@@ -334,14 +617,45 @@ int create_unix_socket(char *file, int len)
err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0){
- printk("create_listening_socket - bind failed, errno = %d\n",
- errno);
+ printk("create_listening_socket at '%s' - bind failed, "
+ "errno = %d\n", file, errno);
return(-errno);
}
return(sock);
}
+void os_flush_stdout(void)
+{
+ fflush(stdout);
+}
+
+int os_lock_file(int fd, int excl)
+{
+ int type = excl ? F_WRLCK : F_RDLCK;
+ struct flock lock = ((struct flock) { .l_type = type,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0 } );
+ int err, save;
+
+ err = fcntl(fd, F_SETLK, &lock);
+ if(!err)
+ goto out;
+
+ save = -errno;
+ err = fcntl(fd, F_GETLK, &lock);
+ if(err){
+ err = -errno;
+ goto out;
+ }
+
+ printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
+ err = save;
+ out:
+ return(err);
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index a97778f3181dd..2cbe598b9df28 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -7,35 +7,44 @@
#include <stdio.h>
#include <errno.h>
#include <signal.h>
+#include <linux/unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include "os.h"
#include "user.h"
+#include "user_util.h"
+
+#define ARBITRARY_ADDR -1
+#define FAILURE_PID -1
+
+#define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
+#define COMM_SCANF "%*[^)])"
unsigned long os_process_pc(int pid)
{
- char proc_stat[sizeof("/proc/#####/stat\0")], buf[256];
+ char proc_stat[STAT_PATH_LEN], buf[256];
unsigned long pc;
- int fd;
+ int fd, err;
sprintf(proc_stat, "/proc/%d/stat", pid);
fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
if(fd < 0){
- printk("os_process_pc - couldn't open '%s', errno = %d\n",
- proc_stat, errno);
- return(-1);
+ printk("os_process_pc - couldn't open '%s', err = %d\n",
+ proc_stat, -fd);
+ return(ARBITRARY_ADDR);
}
- if(read(fd, buf, sizeof(buf)) < 0){
- printk("os_process_pc - couldn't read '%s', errno = %d\n",
- proc_stat, errno);
- close(fd);
- return(-1);
+ err = os_read_file(fd, buf, sizeof(buf));
+ if(err < 0){
+ printk("os_process_pc - couldn't read '%s', err = %d\n",
+ proc_stat, -err);
+ os_close_file(fd);
+ return(ARBITRARY_ADDR);
}
- close(fd);
- pc = -1;
- if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d "
+ os_close_file(fd);
+ pc = ARBITRARY_ADDR;
+ if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d %*d "
"%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%*d %*d %*d %*d %ld", &pc) != 1){
+ "%*d %*d %*d %*d %lu", &pc) != 1){
printk("os_process_pc - couldn't find pc in '%s'\n", buf);
}
return(pc);
@@ -43,7 +52,7 @@ unsigned long os_process_pc(int pid)
int os_process_parent(int pid)
{
- char stat[sizeof("/proc/nnnnn/stat\0")];
+ char stat[STAT_PATH_LEN];
char data[256];
int parent, n, fd;
@@ -52,22 +61,22 @@ int os_process_parent(int pid)
snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
if(fd < 0){
- printk("Couldn't open '%s', errno = %d\n", stat, -fd);
- return(-1);
+ printk("Couldn't open '%s', err = %d\n", stat, -fd);
+ return(FAILURE_PID);
}
- n = read(fd, data, sizeof(data));
- close(fd);
+ n = os_read_file(fd, data, sizeof(data));
+ os_close_file(fd);
if(n < 0){
- printk("Couldn't read '%s', errno = %d\n", stat);
- return(-1);
+ printk("Couldn't read '%s', err = %d\n", stat, -n);
+ return(FAILURE_PID);
}
- parent = -1;
- /* XXX This will break if there is a space in the command */
- n = sscanf(data, "%*d %*s %*c %d", &parent);
- if(n != 1) printk("Failed to scan '%s'\n", data);
+ parent = FAILURE_PID;
+ n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
+ if(n != 1)
+ printk("Failed to scan '%s'\n", data);
return(parent);
}
@@ -81,13 +90,17 @@ void os_kill_process(int pid, int reap_child)
{
kill(pid, SIGKILL);
if(reap_child)
- waitpid(pid, NULL, 0);
+ CATCH_EINTR(waitpid(pid, NULL, 0));
}
void os_usr1_process(int pid)
{
+#ifdef __NR_tkill
+ syscall(__NR_tkill, pid, SIGUSR1);
+#else
kill(pid, SIGUSR1);
+#endif
}
int os_getpid(void)
@@ -95,7 +108,7 @@ int os_getpid(void)
return(getpid());
}
-int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len,
+int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
int r, int w, int x)
{
void *loc;
@@ -104,8 +117,8 @@ int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len,
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
(x ? PROT_EXEC : 0);
- loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
- fd, off);
+ loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
+ fd, off);
if(loc == MAP_FAILED)
return(-errno);
return(0);
@@ -126,7 +139,8 @@ int os_unmap_memory(void *addr, int len)
int err;
err = munmap(addr, len);
- if(err < 0) return(-errno);
+ if(err < 0)
+ return(-errno);
return(0);
}
diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
index 2866ddbc92038..4cfdd18ea1efd 100644
--- a/arch/um/os-Linux/tty.c
+++ b/arch/um/os-Linux/tty.c
@@ -28,10 +28,10 @@ int get_pty(void)
struct grantpt_info info;
int fd;
- if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){
- printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n",
- errno);
- return(-1);
+ fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
+ return(fd);
}
info.fd = fd;
@@ -39,7 +39,7 @@ int get_pty(void)
if(info.res < 0){
printk("get_pty : Couldn't grant pty - errno = %d\n",
- info.err);
+ -info.err);
return(-1);
}
if(unlockpt(fd) < 0){
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
new file mode 100644
index 0000000000000..9b3b606f66b5b
--- /dev/null
+++ b/arch/um/os-Linux/user_syms.c
@@ -0,0 +1,88 @@
+#include "linux/types.h"
+#include "linux/module.h"
+
+/* Some of this are builtin function (some are not but could in the future),
+ * so I *must* declare good prototypes for them and then EXPORT them.
+ * The kernel code uses the macro defined by include/linux/string.h,
+ * so I undef macros; the userspace code does not include that and I
+ * add an EXPORT for the glibc one.*/
+
+#undef strlen
+#undef strstr
+#undef memcpy
+#undef memset
+
+extern size_t strlen(const char *);
+extern void *memcpy(void *, const void *, size_t);
+extern void *memset(void *, int, size_t);
+extern int printf(const char *, ...);
+
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(printf);
+
+EXPORT_SYMBOL(strstr);
+
+/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
+ * However, the modules will use the CRC defined *here*, no matter if it is
+ * good; so the versions of these symbols will always match
+ */
+#define EXPORT_SYMBOL_PROTO(sym) \
+ int sym(void); \
+ EXPORT_SYMBOL(sym);
+
+EXPORT_SYMBOL_PROTO(__errno_location);
+
+EXPORT_SYMBOL_PROTO(access);
+EXPORT_SYMBOL_PROTO(open);
+EXPORT_SYMBOL_PROTO(open64);
+EXPORT_SYMBOL_PROTO(close);
+EXPORT_SYMBOL_PROTO(read);
+EXPORT_SYMBOL_PROTO(write);
+EXPORT_SYMBOL_PROTO(dup2);
+EXPORT_SYMBOL_PROTO(__xstat);
+EXPORT_SYMBOL_PROTO(__lxstat);
+EXPORT_SYMBOL_PROTO(__lxstat64);
+EXPORT_SYMBOL_PROTO(lseek);
+EXPORT_SYMBOL_PROTO(lseek64);
+EXPORT_SYMBOL_PROTO(chown);
+EXPORT_SYMBOL_PROTO(truncate);
+EXPORT_SYMBOL_PROTO(utime);
+EXPORT_SYMBOL_PROTO(chmod);
+EXPORT_SYMBOL_PROTO(rename);
+EXPORT_SYMBOL_PROTO(__xmknod);
+
+EXPORT_SYMBOL_PROTO(symlink);
+EXPORT_SYMBOL_PROTO(link);
+EXPORT_SYMBOL_PROTO(unlink);
+EXPORT_SYMBOL_PROTO(readlink);
+
+EXPORT_SYMBOL_PROTO(mkdir);
+EXPORT_SYMBOL_PROTO(rmdir);
+EXPORT_SYMBOL_PROTO(opendir);
+EXPORT_SYMBOL_PROTO(readdir);
+EXPORT_SYMBOL_PROTO(closedir);
+EXPORT_SYMBOL_PROTO(seekdir);
+EXPORT_SYMBOL_PROTO(telldir);
+
+EXPORT_SYMBOL_PROTO(ioctl);
+
+EXPORT_SYMBOL_PROTO(pread64);
+EXPORT_SYMBOL_PROTO(pwrite64);
+
+EXPORT_SYMBOL_PROTO(statfs);
+EXPORT_SYMBOL_PROTO(statfs64);
+
+EXPORT_SYMBOL_PROTO(getuid);
+
+/*
+ * 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/Makefile b/arch/um/sys-i386/Makefile
index 7525859c549cb..311a42d12b36f 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,14 +1,18 @@
-obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \
- ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
+obj-y = bitops.o bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o \
+ ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o time.o
obj-$(CONFIG_HIGHMEM) += highmem.o
+obj-$(CONFIG_MODULES) += module.o
USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-SYMLINKS = semaphore.c highmem.c module.c
+SYMLINKS = bitops.c semaphore.c highmem.c module.c
SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
+clean-files := $(SYMLINKS)
+
+bitops.c-dir = lib
semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
@@ -24,19 +28,4 @@ $(USER_OBJS) : %.o: %.c
$(SYMLINKS):
$(call make_link,$@)
-clean:
- $(MAKE) -C util clean
-
-fastdep:
-
-dep:
-
-archmrproper:
- rm -f $(SYMLINKS)
-
-archclean:
-
-archdep:
-
-modules:
-
+subdir- := util
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
index 3905bab88902d..9bff9aa6093c9 100644
--- a/arch/um/sys-i386/bugs.c
+++ b/arch/um/sys-i386/bugs.c
@@ -4,20 +4,21 @@
*/
#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/signal.h>
+#include <asm/ldt.h>
#include "kern_util.h"
#include "user.h"
#include "sysdep/ptrace.h"
#include "task.h"
+#include "os.h"
#define MAXTOKEN 64
/* Set during early boot */
-int cpu_has_cmov = 1;
-int cpu_has_xmm = 0;
+int host_has_cmov = 1;
+int host_has_xmm = 0;
static char token(int fd, char *buf, int len, char stop)
{
@@ -27,13 +28,15 @@ static char token(int fd, char *buf, int len, char stop)
ptr = buf;
end = &buf[len];
do {
- n = read(fd, ptr, sizeof(*ptr));
+ n = os_read_file(fd, ptr, sizeof(*ptr));
c = *ptr++;
- if(n == 0) return(0);
- else if(n != sizeof(*ptr)){
- printk("Reading /proc/cpuinfo failed, "
- "errno = %d\n", errno);
- return(-errno);
+ if(n != sizeof(*ptr)){
+ if(n == 0) return(0);
+ printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
+ if(n < 0)
+ return(n);
+ else
+ return(-EIO);
}
} while((c != '\n') && (c != stop) && (ptr < end));
@@ -45,45 +48,79 @@ static char token(int fd, char *buf, int len, char stop)
return(c);
}
-static int check_cpu_feature(char *feature, int *have_it)
+static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
{
- char buf[MAXTOKEN], c;
- int fd, len = sizeof(buf)/sizeof(buf[0]), n;
-
- printk("Checking for host processor %s support...", feature);
- fd = open("/proc/cpuinfo", O_RDONLY);
- if(fd < 0){
- printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno);
- return(0);
- }
+ int n;
+ char c;
- *have_it = 0;
- buf[len - 1] = '\0';
+ scratch[len - 1] = '\0';
while(1){
- c = token(fd, buf, len - 1, ':');
- if(c <= 0) goto out;
+ c = token(fd, scratch, len - 1, ':');
+ if(c <= 0)
+ return(0);
else if(c != ':'){
printk("Failed to find ':' in /proc/cpuinfo\n");
- goto out;
+ return(0);
}
- if(!strncmp(buf, "flags", strlen("flags"))) break;
+ if(!strncmp(scratch, key, strlen(key)))
+ return(1);
do {
- n = read(fd, &c, sizeof(c));
+ n = os_read_file(fd, &c, sizeof(c));
if(n != sizeof(c)){
printk("Failed to find newline in "
- "/proc/cpuinfo, n = %d, errno = %d\n",
- n, errno);
- goto out;
+ "/proc/cpuinfo, err = %d\n", -n);
+ return(0);
}
} while(c != '\n');
}
+ return(0);
+}
+
+int cpu_feature(char *what, char *buf, int len)
+{
+ int fd, ret = 0;
+
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+ return(0);
+ }
+
+ if(!find_cpuinfo_line(fd, what, buf, len)){
+ printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
+ goto out_close;
+ }
+
+ token(fd, buf, len, '\n');
+ ret = 1;
+
+ out_close:
+ os_close_file(fd);
+ return(ret);
+}
+
+static int check_cpu_flag(char *feature, int *have_it)
+{
+ char buf[MAXTOKEN], c;
+ int fd, len = sizeof(buf)/sizeof(buf[0]);
+
+ printk("Checking for host processor %s support...", feature);
+ fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
+ if(fd < 0){
+ printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
+ return(0);
+ }
+
+ *have_it = 0;
+ if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
+ goto out;
c = token(fd, buf, len - 1, ' ');
if(c < 0) goto out;
else if(c != ' '){
- printk("Failed to find ':' in /proc/cpuinfo\n");
+ printk("Failed to find ' ' in /proc/cpuinfo\n");
goto out;
}
@@ -100,21 +137,48 @@ static int check_cpu_feature(char *feature, int *have_it)
out:
if(*have_it == 0) printk("No\n");
else if(*have_it == 1) printk("Yes\n");
- close(fd);
+ os_close_file(fd);
return(1);
}
+#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
+ * for some people.
+ */
+static void disable_lcall(void)
+{
+ struct modify_ldt_ldt_s ldt;
+ int err;
+
+ bzero(&ldt, sizeof(ldt));
+ ldt.entry_number = 7;
+ ldt.base_addr = 0;
+ ldt.limit = 0;
+ err = modify_ldt(1, &ldt, sizeof(ldt));
+ if(err)
+ printk("Failed to disable lcall7 - errno = %d\n", errno);
+}
+#endif
+
+void arch_init_thread(void)
+{
+#if 0
+ disable_lcall();
+#endif
+}
+
void arch_check_bugs(void)
{
int have_it;
- if(access("/proc/cpuinfo", R_OK)){
+ if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
printk("/proc/cpuinfo not available - skipping CPU capability "
"checks\n");
return;
}
- if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it;
- if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it;
+ if(check_cpu_flag("cmov", &have_it))
+ host_has_cmov = have_it;
+ if(check_cpu_flag("xmm", &have_it))
+ host_has_xmm = have_it;
}
int arch_handle_signal(int sig, union uml_pt_regs *regs)
@@ -130,18 +194,18 @@ int arch_handle_signal(int sig, union uml_pt_regs *regs)
if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
return(0);
- if(cpu_has_cmov == 0)
+ if(host_has_cmov == 0)
panic("SIGILL caused by cmov, which this processor doesn't "
"implement, boot a filesystem compiled for older "
"processors");
- else if(cpu_has_cmov == 1)
+ else if(host_has_cmov == 1)
panic("SIGILL caused by cmov, which this processor claims to "
"implement");
- else if(cpu_has_cmov == -1)
+ else if(host_has_cmov == -1)
panic("SIGILL caused by cmov, couldn't tell if this processor "
"implements it, boot a filesystem compiled for older "
"processors");
- else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov);
+ else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
return(0);
}
diff --git a/arch/um/sys-i386/extable.c b/arch/um/sys-i386/extable.c
deleted file mode 100644
index 946e7ad6fbcb6..0000000000000
--- a/arch/um/sys-i386/extable.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * linux/arch/i386/mm/extable.c
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-/* Simple binary search */
-const struct exception_table_entry *
-search_extable(const struct exception_table_entry *first,
- const struct exception_table_entry *last,
- unsigned long value)
-{
- while (first <= last) {
- const struct exception_table_entry *mid;
- long diff;
-
- mid = (last - first) / 2 + first;
- diff = mid->insn - value;
- if (diff == 0)
- return mid;
- else if (diff < 0)
- first = mid+1;
- else
- last = mid-1;
- }
- return NULL;
-}
diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
index 6a0ec334c2a4c..d0bbcdfdb53f0 100644
--- a/arch/um/sys-i386/fault.c
+++ b/arch/um/sys-i386/fault.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -7,16 +7,24 @@
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
-extern unsigned long search_exception_table(unsigned long addr);
+/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
+struct exception_table_entry
+{
+ unsigned long insn;
+ unsigned long fixup;
+};
+const struct exception_table_entry *search_exception_tables(unsigned long add);
+
+/* Compare this to arch/i386/mm/extable.c:fixup_exception() */
int arch_fixup(unsigned long address, void *sc_ptr)
{
struct sigcontext *sc = sc_ptr;
- unsigned long fixup;
+ const struct exception_table_entry *fixup;
fixup = search_exception_tables(address);
if(fixup != 0){
- sc->eip = fixup;
+ sc->eip = fixup->fixup;
return(1);
}
return(0);
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 70da623136161..c6f8d50af5955 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -39,10 +39,10 @@ static void write_debugregs(int pid, unsigned long *regs)
nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
for(i = 0; i < nregs; i++){
if((i == 4) || (i == 5)) continue;
- if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
+ if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i],
regs[i]) < 0)
- printk("write_debugregs - ptrace failed, "
- "errno = %d\n", errno);
+ printk("write_debugregs - ptrace failed on "
+ "register %d, errno = %d\n", errno);
}
}
@@ -54,7 +54,7 @@ static void read_debugregs(int pid, unsigned long *regs)
dummy = NULL;
nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
for(i = 0; i < nregs; i++){
- regs[i] = ptrace(PTRACE_PEEKUSR, pid,
+ regs[i] = ptrace(PTRACE_PEEKUSER, pid,
&dummy->u_debugreg[i], 0);
}
}
diff --git a/arch/um/sys-i386/time.c b/arch/um/sys-i386/time.c
new file mode 100644
index 0000000000000..d9a027f6bf9db
--- /dev/null
+++ b/arch/um/sys-i386/time.c
@@ -0,0 +1,24 @@
+/*
+ * sys-i386/time.c
+ * Created 25.9.2002 Sapan Bhatia
+ *
+ */
+
+unsigned long long time_stamp(void)
+{
+ unsigned long low, high;
+
+ asm("rdtsc" : "=a" (low), "=d" (high));
+ return((((unsigned long long) high) << 32) + low);
+}
+
+/*
+ * 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/util/Makefile b/arch/um/sys-i386/util/Makefile
index 1fd4926b9b5ac..5998287619e57 100644
--- a/arch/um/sys-i386/util/Makefile
+++ b/arch/um/sys-i386/util/Makefile
@@ -1,15 +1,11 @@
-hostprogs-y := mk_sc
-always := $(hostprogs-y) mk_thread
-targets := mk_thread_kern.o mk_thread_user.o
+hostprogs-y := mk_sc mk_thread
+always := $(hostprogs-y)
-mk_sc-objs := mk_sc.o
+mk_thread-objs := mk_thread_kern.o mk_thread_user.o
-$(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o
- $(CC) $(CFLAGS) -o $@ $^
-
-$(obj)/mk_thread_user.o : $(src)/mk_thread_user.c
- $(CC) $(USER_CFLAGS) -c -o $@ $<
+HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS)
+HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS)
clean :
$(RM) -f $(build-targets)
diff --git a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
index 224b6ad756105..85cbd30396f78 100644
--- a/arch/um/sys-i386/util/mk_sc.c
+++ b/arch/um/sys-i386/util/mk_sc.c
@@ -38,6 +38,7 @@ int main(int argc, char **argv)
SC_OFFSET("SC_ERR", err);
SC_OFFSET("SC_CR2", cr2);
SC_OFFSET("SC_FPSTATE", fpstate);
+ SC_OFFSET("SC_SIGMASK", oldmask);
SC_FP_OFFSET("SC_FP_CW", cw);
SC_FP_OFFSET("SC_FP_SW", sw);
SC_FP_OFFSET("SC_FP_TAG", tag);
diff --git a/arch/um/sys-ia64/Makefile b/arch/um/sys-ia64/Makefile
index 4dd735320f705..d02f4c265232a 100644
--- a/arch/um/sys-ia64/Makefile
+++ b/arch/um/sys-ia64/Makefile
@@ -7,18 +7,5 @@ all: $(OBJ)
$(OBJ): $(OBJS)
rm -f $@
$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
-clean:
- rm -f $(OBJS)
-fastdep:
-
-archmrproper:
-
-archclean:
- rm -f link.ld
- @$(MAKEBOOT) clean
-
-archdep:
- @$(MAKEBOOT) dep
-
-modules:
+clean-files := $(OBJS) link.ld
diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile
index 3767c2583026a..af200268fddb8 100644
--- a/arch/um/sys-ppc/Makefile
+++ b/arch/um/sys-ppc/Makefile
@@ -66,13 +66,4 @@ misc.o: misc.S ppc_defs.h
$(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
rm -f asm
-clean:
- rm -f $(OBJS)
- rm -f ppc_defs.h
- rm -f checksum.S semaphore.c mk_defs.c
-
-fastdep:
-
-dep:
-
-modules:
+clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c
diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile
index defd03861eaa2..e2ab71209f3f8 100644
--- a/arch/um/util/Makefile
+++ b/arch/um/util/Makefile
@@ -1,23 +1,8 @@
-always := mk_task mk_constants
-targets := mk_task_user.o mk_task_kern.o \
- mk_constants_user.o mk_constants_kern.o
+hostprogs-y := mk_task mk_constants
+always := $(hostprogs-y)
-$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o
- $(CC) -o $@ $^
+mk_task-objs := mk_task_user.o mk_task_kern.o
+mk_constants-objs := mk_constants_user.o mk_constants_kern.o
-$(obj)/mk_task_user.o: $(src)/mk_task_user.c
- $(CC) -o $@ -c $<
-
-$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o
- $(CC) -o $@ $^
-
-$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c
- $(CC) -c $< -o $@
-
-$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c
- $(CC) $(CFLAGS) -c $< -o $@
-
-clean:
- $(RM) $(build-targets)
-
-archmrproper:
+HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS)
+HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS)
diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c
index 7e74934318c45..cdcb1232a1ea3 100644
--- a/arch/um/util/mk_constants_kern.c
+++ b/arch/um/util/mk_constants_kern.c
@@ -1,5 +1,6 @@
#include "linux/kernel.h"
#include "linux/stringify.h"
+#include "linux/time.h"
#include "asm/page.h"
extern void print_head(void);
@@ -11,6 +12,7 @@ int main(int argc, char **argv)
{
print_head();
print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
+
print_constant_str("UM_KERN_EMERG", KERN_EMERG);
print_constant_str("UM_KERN_ALERT", KERN_ALERT);
print_constant_str("UM_KERN_CRIT", KERN_CRIT);
@@ -19,6 +21,8 @@ int main(int argc, char **argv)
print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
print_constant_str("UM_KERN_INFO", KERN_INFO);
print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
+
+ print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC);
print_tail();
return(0);
}
diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c
index 8e8bf5ddc5831..dacc9b33145b1 100644
--- a/arch/v850/kernel/setup.c
+++ b/arch/v850/kernel/setup.c
@@ -280,8 +280,8 @@ init_mem_alloc (unsigned long ram_start, unsigned long ram_len)
#if ((PAGE_OFFSET >> PAGE_SHIFT) & ((1UL << (MAX_ORDER - 1)) - 1))
#error MAX_ORDER is too large for given PAGE_OFFSET (use CONFIG_FORCE_MAX_ZONEORDER to change it)
#endif
-
- free_area_init_node (0, NODE_DATA(0), 0, zones_size,
+ NODE_DATA(0)->node_mem_map = NULL;
+ free_area_init_node (0, NODE_DATA(0), zones_size,
ADDR_TO_PAGE (PAGE_OFFSET), 0);
mem_map = NODE_DATA(0)->node_mem_map;
}
diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c
index caa9e3a045172..60098e4f06873 100644
--- a/arch/v850/kernel/signal.c
+++ b/arch/v850/kernel/signal.c
@@ -344,9 +344,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -421,9 +419,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
}
/*
diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S
index 71669f7a9e351..bab351c371018 100644
--- a/arch/v850/kernel/vmlinux.lds.S
+++ b/arch/v850/kernel/vmlinux.lds.S
@@ -111,9 +111,6 @@
*(.init.setup) /* 2.5 convention */ \
*(.setup.init) /* 2.4 convention */ \
___setup_end = . ; \
- ___start___param = . ; \
- *(__param) \
- ___stop___param = . ; \
___initcall_start = . ; \
*(.initcall.init) \
*(.initcall1.init) \
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index a0cc03a9055bc..a131337b9dac8 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -347,6 +347,17 @@ config PCI_MMCONFIG
depends on PCI
select ACPI_BOOT
+config UNORDERED_IO
+ bool "Unordered IO mapping access"
+ depends on EXPERIMENTAL
+ select UNORDERED_IO
+ help
+ Use unordered stores to access IO memory mappings in device drivers.
+ Still very experimental. When a driver works on IA64/ppc64/pa-risc it should
+ work with this option, but it makes the drivers behave differently
+ from i386. Requires that the driver writer used memory barriers
+ properly.
+
source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug
index e238651107a38..92059a636b375 100644
--- a/arch/x86_64/Kconfig.debug
+++ b/arch/x86_64/Kconfig.debug
@@ -18,6 +18,18 @@ config INIT_DEBUG
Fill __init and __initdata at the end of boot. This helps debugging
illegal uses of __init and __initdata after initialization.
+config SCHEDSTATS
+ bool "Collect scheduler statistics"
+ depends on DEBUG_KERNEL && PROC_FS
+ help
+ If you say Y here, additional code will be inserted into the
+ scheduler and related routines to collect statistics about
+ scheduler behavior and provide them in /proc/schedstat. These
+ stats may be useful for both tuning and debugging the scheduler
+ If you aren't debugging the scheduler or trying to tune a specific
+ application, you can say N to avoid the very slight overhead
+ this adds.
+
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
help
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 34aa2cebf16c4..7264a361ef3a3 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -77,6 +77,7 @@ boot := arch/x86_64/boot
all: bzImage
BOOTIMAGE := arch/x86_64/boot/bzImage
+KBUILD_IMAGE := $(BOOTIMAGE)
bzImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index bf6969fa0f550..5459d0ab43cc8 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -17,7 +17,6 @@ CONFIG_GENERIC_ISA_DMA=y
#
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
#
# General setup
@@ -29,12 +28,13 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=18
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_IOSCHED_NOOP=y
@@ -104,8 +104,8 @@ CONFIG_ACPI_FAN=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_THERMAL=y
# CONFIG_ACPI_ASUS is not set
-CONFIG_ACPI_TOSHIBA=y
-CONFIG_ACPI_DEBUG=y
+# CONFIG_ACPI_TOSHIBA is not set
+# CONFIG_ACPI_DEBUG is not set
CONFIG_ACPI_BUS=y
CONFIG_ACPI_EC=y
CONFIG_ACPI_POWER=y
@@ -115,7 +115,23 @@ CONFIG_ACPI_SYSTEM=y
#
# CPU Frequency scaling
#
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_PROC_INTF=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_TABLE=y
+
+#
+# CPUFreq processor drivers
+#
+CONFIG_X86_POWERNOW_K8=y
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+CONFIG_X86_ACPI_CPUFREQ=y
+CONFIG_X86_ACPI_CPUFREQ_PROC_INTF=y
#
# Bus options (PCI etc.)
@@ -123,10 +139,27 @@ CONFIG_ACPI_SYSTEM=y
CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
+CONFIG_UNORDERED_IO=y
+CONFIG_PCI_MSI=y
# CONFIG_PCI_LEGACY_PROC is not set
# CONFIG_PCI_NAMES is not set
#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
# Executable file formats / Emulations
#
CONFIG_BINFMT_ELF=y
@@ -144,6 +177,9 @@ CONFIG_UID16=y
#
# Generic Driver Options
#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
#
@@ -171,7 +207,7 @@ CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_CARMEL is not set
+# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
@@ -186,10 +222,10 @@ CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
+# CONFIG_BLK_DEV_IDE_SATA is not set
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_IDEDISK_STROKE is not set
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -234,7 +270,7 @@ CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_SIS5513 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_VIA82CXXX=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
@@ -273,16 +309,24 @@ CONFIG_BLK_DEV_SD=y
# SCSI low-level drivers
#
CONFIG_BLK_DEV_3W_XXXX_RAID=y
+# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_ADVANSYS is not set
+CONFIG_SCSI_AIC79XX=y
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=2000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+# CONFIG_AIC79XX_DEBUG_ENABLE is not set
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
# CONFIG_SCSI_MEGARAID is not set
CONFIG_SCSI_SATA=y
# CONFIG_SCSI_SATA_SVW is not set
CONFIG_SCSI_ATA_PIIX=y
+# CONFIG_SCSI_SATA_NV is not set
# CONFIG_SCSI_SATA_PROMISE is not set
# CONFIG_SCSI_SATA_SX4 is not set
# CONFIG_SCSI_SATA_SIL is not set
@@ -290,7 +334,6 @@ CONFIG_SCSI_ATA_PIIX=y
CONFIG_SCSI_SATA_VIA=y
# CONFIG_SCSI_SATA_VITESSE is not set
# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_PIO is not set
@@ -392,6 +435,7 @@ CONFIG_IPV6=y
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
@@ -431,8 +475,7 @@ CONFIG_MII=y
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
-CONFIG_AMD8111_ETH=y
-# CONFIG_AMD8111E_NAPI is not set
+# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
CONFIG_FORCEDETH=y
@@ -442,16 +485,13 @@ CONFIG_FORCEDETH=y
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
-CONFIG_8139CP=m
-CONFIG_8139TOO=m
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
#
# Ethernet (1000 Mbit)
@@ -602,6 +642,9 @@ CONFIG_AGP_AMD64=y
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
CONFIG_RAW_DRIVER=y
+CONFIG_HPET=y
+# CONFIG_HPET_RTC_IRQ is not set
+CONFIG_HPET_MMAP=y
CONFIG_MAX_RAW_DEVS=256
CONFIG_HANGCHECK_TIMER=y
@@ -611,6 +654,11 @@ CONFIG_HANGCHECK_TIMER=y
# CONFIG_I2C is not set
#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
# Misc devices
#
# CONFIG_IBM_ASM is not set
@@ -703,17 +751,8 @@ CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_BLUETOOTH_TTY is not set
# CONFIG_USB_MIDI is not set
# CONFIG_USB_ACM is not set
-CONFIG_USB_PRINTER=y
-CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_STORAGE is not set
#
# USB Human Interface Devices (HID)
@@ -830,7 +869,8 @@ CONFIG_ISO9660_FS=y
#
# DOS/FAT/NT Filesystems
#
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
# CONFIG_NTFS_FS is not set
#
@@ -856,6 +896,7 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -909,10 +950,11 @@ CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SLAB is not set
CONFIG_MAGIC_SYSRQ=y
# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_INIT_DEBUG is not set
+CONFIG_INIT_DEBUG=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_FRAME_POINTER is not set
-# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IOMMU_DEBUG=y
+# CONFIG_IOMMU_LEAK is not set
#
# Security options
@@ -927,5 +969,6 @@ CONFIG_MAGIC_SYSRQ=y
#
# Library routines
#
+# CONFIG_CRC_CCITT is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 8e6b845f7cb90..195cacb69ba73 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -301,6 +301,9 @@ MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
#define elf_addr_t __u32
+#undef TASK_SIZE
+#define TASK_SIZE 0xffffffff
+
static void elf32_init(struct pt_regs *);
#include "../../../fs/binfmt_elf.c"
diff --git a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
index 8c6964245bfab..d259f8a6f811d 100644
--- a/arch/x86_64/ia32/ia32_ioctl.c
+++ b/arch/x86_64/ia32/ia32_ioctl.c
@@ -171,23 +171,8 @@ struct ioctl_trans ioctl_start[] = {
COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(BLKFRASET)
COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(RTC_AIE_ON)
-COMPATIBLE_IOCTL(RTC_AIE_OFF)
-COMPATIBLE_IOCTL(RTC_UIE_ON)
-COMPATIBLE_IOCTL(RTC_UIE_OFF)
-COMPATIBLE_IOCTL(RTC_PIE_ON)
-COMPATIBLE_IOCTL(RTC_PIE_OFF)
-COMPATIBLE_IOCTL(RTC_WIE_ON)
-COMPATIBLE_IOCTL(RTC_WIE_OFF)
-COMPATIBLE_IOCTL(RTC_ALM_SET)
-COMPATIBLE_IOCTL(RTC_ALM_READ)
-COMPATIBLE_IOCTL(RTC_RD_TIME)
-COMPATIBLE_IOCTL(RTC_SET_TIME)
-COMPATIBLE_IOCTL(RTC_WKALM_SET)
-COMPATIBLE_IOCTL(RTC_WKALM_RD)
COMPATIBLE_IOCTL(FIOQSIZE)
/* And these ioctls need translation */
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 5716c8bec3ce9..b5b77dbf3b400 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -115,7 +115,8 @@ int ia32_copy_siginfo_from_user(siginfo_t *to, siginfo_t32 __user *from)
}
asmlinkage long
-sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
+sys32_sigsuspend(int history0, int history1, old_sigset_t mask,
+ struct pt_regs *regs)
{
sigset_t saveset;
@@ -126,11 +127,11 @@ sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs r
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs.rax = -EINTR;
+ regs->rax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&regs, &saveset))
+ if (do_signal(regs, &saveset))
return -EINTR;
}
}
@@ -138,7 +139,7 @@ sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs r
asmlinkage long
sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
stack_ia32_t __user *uoss_ptr,
- struct pt_regs regs)
+ struct pt_regs *regs)
{
stack_t uss,uoss;
int ret;
@@ -155,7 +156,7 @@ sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
}
seg = get_fs();
set_fs(KERNEL_DS);
- ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp);
+ ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->rsp);
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
@@ -274,9 +275,9 @@ badframe:
return 1;
}
-asmlinkage long sys32_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_sigreturn(struct pt_regs *regs)
{
- struct sigframe __user *frame = (struct sigframe __user *)(regs.rsp-8);
+ struct sigframe __user *frame = (struct sigframe __user *)(regs->rsp-8);
sigset_t set;
unsigned int eax;
@@ -294,20 +295,23 @@ asmlinkage long sys32_sigreturn(struct pt_regs regs)
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- if (ia32_restore_sigcontext(&regs, &frame->sc, &eax))
+ if (ia32_restore_sigcontext(regs, &frame->sc, &eax))
goto badframe;
return eax;
badframe:
- signal_fault(&regs, frame, "32bit sigreturn");
+ signal_fault(regs, frame, "32bit sigreturn");
return 0;
}
-asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
{
- struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs.rsp - 4);
+ struct rt_sigframe __user *frame;
sigset_t set;
unsigned int eax;
+ struct pt_regs tregs;
+
+ frame = (struct rt_sigframe __user *)(regs->rsp - 4);
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -320,16 +324,17 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
+ if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
goto badframe;
- if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, regs) == -EFAULT)
+ tregs = *regs;
+ if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
goto badframe;
return eax;
badframe:
- signal_fault(&regs,frame,"32bit rt sigreturn");
+ signal_fault(regs,frame,"32bit rt sigreturn");
return 0;
}
@@ -494,9 +499,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- signal_fault(regs,frame,"32bit signal deliver");
+ force_sigsegv(sig, current);
}
void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -590,8 +593,6 @@ void ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- signal_fault(regs, frame, "32bit rt signal setup");
+ force_sigsegv(sig, current);
}
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 0a2fb66b67467..9fd8d5b3471de 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -270,35 +270,32 @@ quiet_ni_syscall:
ret
CFI_ENDPROC
- .macro PTREGSCALL label, func
+ .macro PTREGSCALL label, func, arg
.globl \label
\label:
leaq \func(%rip),%rax
+ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
jmp ia32_ptregs_common
.endm
- PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn
- PTREGSCALL stub32_sigreturn, sys32_sigreturn
- PTREGSCALL stub32_sigaltstack, sys32_sigaltstack
- PTREGSCALL stub32_sigsuspend, sys32_sigsuspend
- PTREGSCALL stub32_execve, sys32_execve
- PTREGSCALL stub32_fork, sys_fork
- PTREGSCALL stub32_clone, sys32_clone
- PTREGSCALL stub32_vfork, sys_vfork
- PTREGSCALL stub32_iopl, sys_iopl
- PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend
+ PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
+ PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
+ PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
+ PTREGSCALL stub32_sigsuspend, sys32_sigsuspend, %rcx
+ PTREGSCALL stub32_execve, sys32_execve, %rcx
+ PTREGSCALL stub32_fork, sys_fork, %rdi
+ PTREGSCALL stub32_clone, sys32_clone, %rdx
+ PTREGSCALL stub32_vfork, sys_vfork, %rdi
+ PTREGSCALL stub32_iopl, sys_iopl, %rsi
+ PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx
ENTRY(ia32_ptregs_common)
CFI_STARTPROC
popq %r11
SAVE_REST
- movq %r11, %r15
call *%rax
- movq %r15, %r11
RESTORE_REST
- leaq ia32_sysret(%rip),%r11
- pushq %r11
- ret
+ jmp ia32_sysret /* misbalances the return cache */
CFI_ENDPROC
.data
@@ -332,7 +329,7 @@ ia32_sys_call_table:
.quad sys_getuid16
.quad sys_stime /* stime */ /* 25 */
.quad sys32_ptrace /* ptrace */
- .quad sys_alarm /* XXX sign extension??? */
+ .quad sys_alarm
.quad sys_fstat /* (old)fstat */
.quad sys_pause
.quad compat_sys_utime /* 30 */
@@ -558,7 +555,7 @@ ia32_sys_call_table:
.quad sys_fadvise64 /* 250 */
.quad quiet_ni_syscall /* free_huge_pages */
.quad sys_exit_group
- .quad sys_lookup_dcookie
+ .quad sys32_lookup_dcookie
.quad sys_epoll_create
.quad sys_epoll_ctl /* 255 */
.quad sys_epoll_wait
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
index 01202b792eb96..4445da812ecf6 100644
--- a/arch/x86_64/ia32/ptrace32.c
+++ b/arch/x86_64/ia32/ptrace32.c
@@ -249,8 +249,8 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
case PTRACE_GETFPREGS:
case PTRACE_SETFPXREGS:
case PTRACE_GETFPXREGS:
+ case PTRACE_GETEVENTMSG:
break;
-
}
child = find_target(request, pid, &ret);
@@ -363,6 +363,10 @@ asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
break;
}
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message,(unsigned int __user *)(u64)data);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 00f6e151639a2..6a33dbb93b71d 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -1125,7 +1125,7 @@ long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
}
asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs regs)
+ compat_uptr_t __user *envp, struct pt_regs *regs)
{
long error;
char * filename;
@@ -1134,21 +1134,21 @@ asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = compat_do_execve(filename, argv, envp, &regs);
+ error = compat_do_execve(filename, argv, envp, regs);
if (error == 0)
current->ptrace &= ~PT_DTRACE;
putname(filename);
return error;
}
-asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
+asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
+ struct pt_regs *regs)
{
- void __user *parent_tid = (void __user *)regs.rdx;
- void __user *child_tid = (void __user *)regs.rdi;
+ void __user *parent_tid = (void __user *)regs->rdx;
+ void __user *child_tid = (void __user *)regs->rdi;
if (!newsp)
- newsp = regs.rsp;
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
- parent_tid, child_tid);
+ newsp = regs->rsp;
+ return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
/*
@@ -1337,6 +1337,12 @@ long sys32_quotactl(void)
return -ENOSYS;
}
+long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
+ char __user * buf, size_t len)
+{
+ return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
+}
+
cond_syscall(sys32_ipc)
static int __init ia32_init (void)
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index 5ec45f513bd4c..e70de986a7292 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
-obj-$(CONFIG_SCHED_SMT) += domain.o
obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/x86_64/kernel/Makefile-HEAD b/arch/x86_64/kernel/Makefile-HEAD
deleted file mode 100644
index 5ec45f513bd4c..0000000000000
--- a/arch/x86_64/kernel/Makefile-HEAD
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-extra-y := head.o head64.o init_task.o vmlinux.lds
-EXTRA_AFLAGS := -traditional
-obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \
- ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \
- x8664_ksyms.o i387.o syscall.o vsyscall.o \
- setup64.o bootflag.o e820.o reboot.o warmreboot.o
-obj-y += mce.o
-
-obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/
-obj-$(CONFIG_ACPI_BOOT) += acpi/
-obj-$(CONFIG_X86_MSR) += msr.o
-obj-$(CONFIG_MICROCODE) += microcode.o
-obj-$(CONFIG_X86_CPUID) += cpuid.o
-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
-obj-$(CONFIG_PM) += suspend.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
-obj-$(CONFIG_CPU_FREQ) += cpufreq/
-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
-obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o pci-dma.o
-obj-$(CONFIG_SWIOTLB) += swiotlb.o
-obj-$(CONFIG_SCHED_SMT) += domain.o
-
-obj-$(CONFIG_MODULES) += module.o
-
-obj-y += topology.o
-
-bootflag-y += ../../i386/kernel/bootflag.o
-cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o
-topology-y += ../../i386/mach-default/topology.o
-swiotlb-$(CONFIG_SWIOTLB) += ../../ia64/lib/swiotlb.o
-microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index 164b6d0785326..1d8b3912c1d90 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -31,6 +31,8 @@ int iommu_aperture_allowed __initdata = 0;
int fallback_aper_order __initdata = 1; /* 64MB */
int fallback_aper_force __initdata = 0;
+int fix_aperture __initdata = 1;
+
/* This code runs before the PCI subsystem is initialized, so just
access the northbridge directly. */
@@ -202,7 +204,7 @@ void __init iommu_hole_init(void)
u64 aper_base;
int valid_agp = 0;
- if (iommu_aperture_disabled)
+ if (iommu_aperture_disabled || !fix_aperture)
return;
printk("Checking aperture...\n");
@@ -241,20 +243,15 @@ void __init iommu_hole_init(void)
/* Got the aperture from the AGP bridge */
} else if ((!no_iommu && end_pfn >= 0xffffffff>>PAGE_SHIFT) ||
force_iommu ||
- valid_agp ||
+ valid_agp ||
fallback_aper_force) {
- /* When there is a AGP bridge in the system assume the
- user wants to use the AGP driver too and needs an
- aperture. However this case (AGP but no good
- aperture) should only happen with a more broken than
- usual BIOS, because it would even break Windows. */
-
- printk("Your BIOS doesn't leave a aperture memory hole\n");
- printk("Please enable the IOMMU option in the BIOS setup\n");
- printk("This costs you %d MB of RAM\n", 32 << fallback_aper_order);
-
+ printk("Your BIOS doesn't leave a aperture memory hole\n");
+ printk("Please enable the IOMMU option in the BIOS setup\n");
+ printk("This costs you %d MB of RAM\n",
+ 32 << fallback_aper_order);
+
aper_order = fallback_aper_order;
- aper_alloc = allocate_aperture();
+ aper_alloc = allocate_aperture();
if (!aper_alloc) {
/* Could disable AGP and IOMMU here, but it's probably
not worth it. But the later users cannot deal with
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
index 284023945a3b6..dcb518eb2831e 100644
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -46,4 +46,53 @@ config X86_POWERNOW_K8_ACPI
depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
default y
+config X86_SPEEDSTEP_CENTRINO
+ tristate "Intel Enhanced SpeedStep"
+ depends on CPU_FREQ_TABLE
+ help
+ This adds the CPUFreq driver for Enhanced SpeedStep enabled
+ mobile CPUs. This means Intel Pentium M (Centrino) CPUs
+ or 64bit enabled Intel Xeons.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+config X86_SPEEDSTEP_CENTRINO_TABLE
+ bool
+ depends on X86_SPEEDSTEP_CENTRINO
+ default y
+
+config X86_SPEEDSTEP_CENTRINO_ACPI
+ bool "Use ACPI tables to decode valid frequency/voltage pairs (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
+ help
+ Use primarily the information provided in the BIOS ACPI tables
+ to determine valid CPU frequency and voltage pairings.
+
+ If in doubt, say Y.
+
+config X86_ACPI_CPUFREQ
+ tristate "ACPI Processor P-States driver"
+ depends on CPU_FREQ_TABLE && ACPI_PROCESSOR
+ help
+ This driver adds a CPUFreq driver which utilizes the ACPI
+ Processor Performance States.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+config X86_ACPI_CPUFREQ_PROC_INTF
+ bool "/proc/acpi/processor/../performance interface (deprecated)"
+ depends on X86_ACPI_CPUFREQ && PROC_FS
+ help
+ This enables the deprecated /proc/acpi/processor/../performance
+ interface. While it is helpful for debugging, the generic,
+ cross-architecture cpufreq interfaces should be used.
+
+ If in doubt, say N.
+
endmenu
+
diff --git a/arch/x86_64/kernel/cpufreq/Makefile b/arch/x86_64/kernel/cpufreq/Makefile
index f02ed52be0d9f..d0f0b2cf343b1 100644
--- a/arch/x86_64/kernel/cpufreq/Makefile
+++ b/arch/x86_64/kernel/cpufreq/Makefile
@@ -2,6 +2,12 @@
# Reuse the i386 cpufreq drivers
#
+SRCDIR := ../../../i386/kernel/cpu/cpufreq
+
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
+obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o
-powernow-k8-objs := ../../../i386/kernel/cpu/cpufreq/powernow-k8.o
+powernow-k8-objs := ${SRCDIR}/powernow-k8.o
+speedstep-centrino-objs := ${SRCDIR}/speedstep-centrino.o
+acpi-objs := ${SRCDIR}/acpi.o
diff --git a/arch/x86_64/kernel/domain.c b/arch/x86_64/kernel/domain.c
deleted file mode 100644
index 0694958c7801e..0000000000000
--- a/arch/x86_64/kernel/domain.c
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <linux/init.h>
-#include <linux/sched.h>
-
-/* Don't do any NUMA setup on Opteron right now. They seem to be
- better off with flat scheduling. This is just for SMT. */
-
-#ifdef CONFIG_SCHED_SMT
-
-static struct sched_group sched_group_cpus[NR_CPUS];
-static struct sched_group sched_group_phys[NR_CPUS];
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
-static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-__init void arch_init_sched_domains(void)
-{
- int i;
- struct sched_group *first = NULL, *last = NULL;
-
- /* Set up domains */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_domain *phys_domain = &per_cpu(phys_domains, i);
-
- *cpu_domain = SD_SIBLING_INIT;
- /* Disable SMT NICE for CMP */
- /* RED-PEN use a generic flag */
- if (cpu_data[i].x86_vendor == X86_VENDOR_AMD)
- cpu_domain->flags &= ~SD_SHARE_CPUPOWER;
- cpu_domain->span = cpu_sibling_map[i];
- cpu_domain->parent = phys_domain;
- cpu_domain->groups = &sched_group_cpus[i];
-
- *phys_domain = SD_CPU_INIT;
- phys_domain->span = cpu_possible_map;
- phys_domain->groups = &sched_group_phys[first_cpu(cpu_domain->span)];
- }
-
- /* Set up CPU (sibling) groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- int j;
- first = last = NULL;
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- for_each_cpu_mask(j, cpu_domain->span) {
- struct sched_group *cpu = &sched_group_cpus[j];
-
- cpus_clear(cpu->cpumask);
- cpu_set(j, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
- }
-
- first = last = NULL;
- /* Set up physical groups */
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- struct sched_group *cpu = &sched_group_phys[i];
-
- if (i != first_cpu(cpu_domain->span))
- continue;
-
- cpu->cpumask = cpu_domain->span;
- /*
- * Make each extra sibling increase power by 10% of
- * the basic CPU. This is very arbitrary.
- */
- cpu->cpu_power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE*(cpus_weight(cpu->cpumask)-1) / 10;
-
- if (!first)
- first = cpu;
- if (last)
- last->next = cpu;
- last = cpu;
- }
- last->next = first;
-
- mb();
- for_each_cpu(i) {
- struct sched_domain *cpu_domain = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_domain, i);
- }
-}
-
-#endif
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index 98041f50e0ea8..785f792839d52 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -99,18 +99,17 @@ static void early_serial_write(struct console *con, const char *s, unsigned n)
#define DEFAULT_BAUD 9600
-static __init void early_serial_init(char *opt)
+static __init void early_serial_init(char *s)
{
unsigned char c;
unsigned divisor;
unsigned baud = DEFAULT_BAUD;
- char *s, *e;
+ char *e;
- if (*opt == ',')
- ++opt;
+ if (*s == ',')
+ ++s;
- s = strsep(&opt, ",");
- if (s != NULL) {
+ if (*s) {
unsigned port;
if (!strncmp(s,"0x",2)) {
early_serial_base = simple_strtoul(s, &e, 16);
@@ -124,6 +123,9 @@ static __init void early_serial_init(char *opt)
port = 0;
early_serial_base = bases[port];
}
+ s += strcspn(s, ",");
+ if (*s == ',')
+ s++;
}
outb(0x3, early_serial_base + LCR); /* 8n1 */
@@ -131,8 +133,7 @@ static __init void early_serial_init(char *opt)
outb(0, early_serial_base + FCR); /* no fifo */
outb(0x3, early_serial_base + MCR); /* DTR + RTS */
- s = strsep(&opt, ",");
- if (s != NULL) {
+ if (*s) {
baud = simple_strtoul(s, &e, 0);
if (baud == 0 || s == e)
baud = DEFAULT_BAUD;
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index cf008e67422ff..17d74eb66ae87 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -324,19 +324,20 @@ int_restore_rest:
* Certain special system calls that need to save a complete full stack frame.
*/
- .macro PTREGSCALL label,func
+ .macro PTREGSCALL label,func,arg
.globl \label
\label:
leaq \func(%rip),%rax
+ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
jmp ptregscall_common
.endm
- PTREGSCALL stub_clone, sys_clone
- PTREGSCALL stub_fork, sys_fork
- PTREGSCALL stub_vfork, sys_vfork
- PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend
- PTREGSCALL stub_sigaltstack, sys_sigaltstack
- PTREGSCALL stub_iopl, sys_iopl
+ PTREGSCALL stub_clone, sys_clone, %r8
+ PTREGSCALL stub_fork, sys_fork, %rdi
+ PTREGSCALL stub_vfork, sys_vfork, %rdi
+ PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend, %rdx
+ PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
+ PTREGSCALL stub_iopl, sys_iopl, %rsi
ENTRY(ptregscall_common)
CFI_STARTPROC
@@ -386,6 +387,7 @@ ENTRY(stub_rt_sigreturn)
CFI_STARTPROC
addq $8, %rsp
SAVE_REST
+ movq %rsp,%rdi
FIXUP_TOP_OF_STACK %r11
call sys_rt_sigreturn
movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c
index 0a90fd08fadd9..12450b55fa7e1 100644
--- a/arch/x86_64/kernel/ioport.c
+++ b/arch/x86_64/kernel/ioport.c
@@ -83,9 +83,9 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
* code.
*/
-asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs)
+asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs)
{
- unsigned int old = (regs.eflags >> 12) & 3;
+ unsigned int old = (regs->eflags >> 12) & 3;
if (level > 3)
return -EINVAL;
@@ -94,6 +94,6 @@ asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs)
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
}
- regs.eflags = (regs.eflags &~ 0x3000UL) | (level << 12);
+ regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12);
return 0;
}
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 0399360a18eb2..432f799708d5a 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -24,7 +24,8 @@
#define MISC_MCELOG_MINOR 227
#define NR_BANKS 5
-static int mce_disabled __initdata;
+static int mce_dont_init;
+
/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
3: never panic or exit (for testing only) */
static int tolerant = 1;
@@ -113,9 +114,8 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start)
static int mce_available(struct cpuinfo_x86 *c)
{
- return !mce_disabled &&
- test_bit(X86_FEATURE_MCE, &c->x86_capability) &&
- test_bit(X86_FEATURE_MCA, &c->x86_capability);
+ return test_bit(X86_FEATURE_MCE, &c->x86_capability) &&
+ test_bit(X86_FEATURE_MCA, &c->x86_capability);
}
/*
@@ -127,8 +127,9 @@ void do_machine_check(struct pt_regs * regs, long error_code)
struct mce m, panicm;
int nowayout = (tolerant < 1);
int kill_it = 0;
- u64 mcestart;
+ u64 mcestart = 0;
int i;
+ int panicm_found = 0;
if (regs)
notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
@@ -138,17 +139,11 @@ void do_machine_check(struct pt_regs * regs, long error_code)
memset(&m, 0, sizeof(struct mce));
m.cpu = hard_smp_processor_id();
rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
- if (!regs && (m.mcgstatus & MCG_STATUS_MCIP))
- return;
if (!(m.mcgstatus & MCG_STATUS_RIPV))
kill_it = 1;
- if (regs) {
- m.rip = regs->rip;
- m.cs = regs->cs;
- }
rdtscll(mcestart);
- mb();
+ barrier();
for (i = 0; i < banks; i++) {
if (!bank[i])
@@ -156,52 +151,62 @@ void do_machine_check(struct pt_regs * regs, long error_code)
m.misc = 0;
m.addr = 0;
+ m.bank = i;
+ m.tsc = 0;
rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
if ((m.status & MCI_STATUS_VAL) == 0)
continue;
- /* Should be implied by the banks check above, but
- check it anyways */
- if ((m.status & MCI_STATUS_EN) == 0)
- continue;
- /* Did this bank cause the exception? */
- /* Assume that the bank with uncorrectable errors did it,
- and that there is only a single one. */
- if (m.status & MCI_STATUS_UC) {
- panicm = m;
- } else {
- m.rip = 0;
- m.cs = 0;
+ if (m.status & MCI_STATUS_EN) {
+ /* In theory _OVER could be a nowayout too, but
+ assume any overflowed errors were no fatal. */
+ nowayout |= !!(m.status & MCI_STATUS_PCC);
+ kill_it |= !!(m.status & MCI_STATUS_UC);
}
- /* In theory _OVER could be a nowayout too, but
- assume any overflowed errors were no fatal. */
- nowayout |= !!(m.status & MCI_STATUS_PCC);
- kill_it |= !!(m.status & MCI_STATUS_UC);
- m.bank = i;
-
if (m.status & MCI_STATUS_MISCV)
rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
if (m.status & MCI_STATUS_ADDRV)
rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
- rdtscll(m.tsc);
+ if (regs && (m.mcgstatus & MCG_STATUS_RIPV)) {
+ m.rip = regs->rip;
+ m.cs = regs->cs;
+ } else {
+ m.rip = 0;
+ m.cs = 0;
+ }
+
+ if (error_code != -1)
+ rdtscll(m.tsc);
wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
mce_log(&m);
+
+ /* Did this bank cause the exception? */
+ /* Assume that the bank with uncorrectable errors did it,
+ and that there is only a single one. */
+ if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) {
+ panicm = m;
+ panicm_found = 1;
+ }
}
- wrmsrl(MSR_IA32_MCG_STATUS, 0);
/* Never do anything final in the polling timer */
if (!regs)
- return;
+ goto out;
+
+ /* If we didn't find an uncorrectable error, pick
+ the last one (shouldn't happen, just being safe). */
+ if (!panicm_found)
+ panicm = m;
if (nowayout)
- mce_panic("Machine check", &m, mcestart);
+ mce_panic("Machine check", &panicm, mcestart);
if (kill_it) {
int user_space = 0;
if (m.mcgstatus & MCG_STATUS_RIPV)
- user_space = m.rip && (m.cs & 3);
+ user_space = panicm.rip && (panicm.cs & 3);
/* When the machine was in user space and the CPU didn't get
confused it's normally not necessary to panic, unless you
@@ -214,18 +219,15 @@ void do_machine_check(struct pt_regs * regs, long error_code)
(unsigned)current->pid <= 1)
mce_panic("Uncorrected machine check", &panicm, mcestart);
- /* do_exit takes an awful lot of locks and has as slight risk
- of deadlocking. If you don't want that don't set tolerant >= 2 */
+ /* do_exit takes an awful lot of locks and has as
+ slight risk of deadlocking. If you don't want that
+ don't set tolerant >= 2 */
if (tolerant < 3)
do_exit(SIGBUS);
}
-}
-static void mce_clear_all(void)
-{
- int i;
- for (i = 0; i < banks; i++)
- wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
+ out:
+ /* Last thing done in the machine check exception to clear state. */
wrmsrl(MSR_IA32_MCG_STATUS, 0);
}
@@ -268,22 +270,25 @@ static void mce_init(void *dummy)
int i;
rdmsrl(MSR_IA32_MCG_CAP, cap);
- if (cap & MCG_CTL_P)
- wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
-
banks = cap & 0xff;
if (banks > NR_BANKS) {
printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
banks = NR_BANKS;
}
- mce_clear_all();
+ /* Log the machine checks left over from the previous reset.
+ This also clears all registers */
+ do_machine_check(NULL, -1);
+
+ set_in_cr4(X86_CR4_MCE);
+
+ if (cap & MCG_CTL_P)
+ wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+
for (i = 0; i < banks; i++) {
wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
}
-
- set_in_cr4(X86_CR4_MCE);
}
/* Add per CPU specific workarounds here */
@@ -307,7 +312,9 @@ void __init mcheck_init(struct cpuinfo_x86 *c)
mce_cpu_quirks(c);
- if (test_and_set_bit(smp_processor_id(), &mce_cpus) || !mce_available(c))
+ if (mce_dont_init ||
+ test_and_set_bit(smp_processor_id(), &mce_cpus) ||
+ !mce_available(c))
return;
mce_init(NULL);
@@ -410,15 +417,16 @@ static struct miscdevice mce_log_device = {
static int __init mcheck_disable(char *str)
{
- mce_disabled = 1;
+ mce_dont_init = 1;
return 0;
}
-/* mce=off disable machine check */
+/* mce=off disables machine check. Note you can reenable it later
+ using sysfs */
static int __init mcheck_enable(char *str)
{
if (!strcmp(str, "off"))
- mce_disabled = 1;
+ mce_dont_init = 1;
else
printk("mce= argument %s ignored. Please use /sys", str);
return 0;
@@ -434,7 +442,6 @@ __setup("mce", mcheck_enable);
/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */
static int mce_resume(struct sys_device *dev)
{
- mce_clear_all();
on_each_cpu(mce_init, NULL, 1, 1);
return 0;
}
@@ -492,7 +499,7 @@ static __init int mce_init_device(void)
if (!err)
err = sysdev_register(&device_mce);
if (!err) {
- /* could create per CPU objects, but is not worth it. */
+ /* could create per CPU objects, but it is not worth it. */
sysdev_create_file(&device_mce, &attr_bank0ctl);
sysdev_create_file(&device_mce, &attr_bank1ctl);
sysdev_create_file(&device_mce, &attr_bank2ctl);
diff --git a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c
index 654e4578d021e..89ad3e72947f5 100644
--- a/arch/x86_64/kernel/msr.c
+++ b/arch/x86_64/kernel/msr.c
@@ -46,234 +46,229 @@
static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
{
- int err;
-
- asm volatile(
- "1: wrmsr\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- "3: movl %4,%0\n"
- " jmp 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,3b\n"
- ".previous"
- : "=&bDS" (err)
- : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0));
-
- return err;
+ int err;
+
+ asm volatile ("1: wrmsr\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: movl %4,%0\n"
+ " jmp 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n" " .quad 1b,3b\n" ".previous":"=&bDS" (err)
+ :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0));
+
+ return err;
}
static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
{
- int err;
-
- asm volatile(
- "1: rdmsr\n"
- "2:\n"
- ".section .fixup,\"ax\"\n"
- "3: movl %4,%0\n"
- " jmp 2b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,3b\n"
- ".previous"
- : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
- : "c" (reg), "i" (-EIO), "0" (0));
-
- return err;
+ int err;
+
+ asm volatile ("1: rdmsr\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: movl %4,%0\n"
+ " jmp 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 1b,3b\n"
+ ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx)
+ :"c"(reg), "i"(-EIO), "0"(0));
+
+ return err;
}
#ifdef CONFIG_SMP
struct msr_command {
- int cpu;
- int err;
- u32 reg;
- u32 data[2];
+ int cpu;
+ int err;
+ u32 reg;
+ u32 data[2];
};
static void msr_smp_wrmsr(void *cmd_block)
{
- struct msr_command *cmd = (struct msr_command *) cmd_block;
-
- if ( cmd->cpu == smp_processor_id() )
- cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
+ struct msr_command *cmd = (struct msr_command *)cmd_block;
+
+ if (cmd->cpu == smp_processor_id())
+ cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
}
static void msr_smp_rdmsr(void *cmd_block)
{
- struct msr_command *cmd = (struct msr_command *) cmd_block;
-
- if ( cmd->cpu == smp_processor_id() )
- cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
+ struct msr_command *cmd = (struct msr_command *)cmd_block;
+
+ if (cmd->cpu == smp_processor_id())
+ cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
}
static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
{
- struct msr_command cmd;
- int ret;
-
- preempt_disable();
- if ( cpu == smp_processor_id() ) {
- ret = wrmsr_eio(reg, eax, edx);
- } else {
- cmd.cpu = cpu;
- cmd.reg = reg;
- cmd.data[0] = eax;
- cmd.data[1] = edx;
-
- smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
- ret = cmd.err;
- }
- preempt_enable();
- return ret;
+ struct msr_command cmd;
+ int ret;
+
+ preempt_disable();
+ if (cpu == smp_processor_id()) {
+ ret = wrmsr_eio(reg, eax, edx);
+ } else {
+ cmd.cpu = cpu;
+ cmd.reg = reg;
+ cmd.data[0] = eax;
+ cmd.data[1] = edx;
+
+ smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
+ ret = cmd.err;
+ }
+ preempt_enable();
+ return ret;
}
-static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx)
{
- struct msr_command cmd;
- int ret;
-
- preempt_disable();
- if ( cpu == smp_processor_id() ) {
- ret = rdmsr_eio(reg, eax, edx);
- } else {
- cmd.cpu = cpu;
- cmd.reg = reg;
-
- smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
-
- *eax = cmd.data[0];
- *edx = cmd.data[1];
-
- ret = cmd.err;
- }
- preempt_enable();
- return ret;
+ struct msr_command cmd;
+ int ret;
+
+ preempt_disable();
+ if (cpu == smp_processor_id()) {
+ ret = rdmsr_eio(reg, eax, edx);
+ } else {
+ cmd.cpu = cpu;
+ cmd.reg = reg;
+
+ smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
+
+ *eax = cmd.data[0];
+ *edx = cmd.data[1];
+
+ ret = cmd.err;
+ }
+ preempt_enable();
+ return ret;
}
-#else /* ! CONFIG_SMP */
+#else /* ! CONFIG_SMP */
static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
{
- return wrmsr_eio(reg, eax, edx);
+ return wrmsr_eio(reg, eax, edx);
}
static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
{
- return rdmsr_eio(reg, eax, edx);
+ return rdmsr_eio(reg, eax, edx);
}
-#endif /* ! CONFIG_SMP */
+#endif /* ! CONFIG_SMP */
static loff_t msr_seek(struct file *file, loff_t offset, int orig)
{
- loff_t ret = -EINVAL;
- lock_kernel();
- switch (orig) {
- case 0:
- file->f_pos = offset;
- ret = file->f_pos;
- break;
- case 1:
- file->f_pos += offset;
- ret = file->f_pos;
- }
- unlock_kernel();
- return ret;
+ loff_t ret = -EINVAL;
+
+ lock_kernel();
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ ret = file->f_pos;
+ break;
+ case 1:
+ file->f_pos += offset;
+ ret = file->f_pos;
+ }
+ unlock_kernel();
+ return ret;
}
-static ssize_t msr_read(struct file * file, char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t msr_read(struct file *file, char __user * buf,
+ size_t count, loff_t * ppos)
{
- char __user *tmp = buf;
- u32 data[2];
- size_t rv;
- u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
- int err;
-
- if ( count % 8 )
- return -EINVAL; /* Invalid chunk size */
-
- for ( rv = 0 ; count ; count -= 8 ) {
- err = do_rdmsr(cpu, reg, &data[0], &data[1]);
- if ( err )
- return err;
- if ( copy_to_user(tmp,&data,8) )
- return -EFAULT;
- tmp += 8;
- }
-
- return tmp - buf;
+ u32 __user *tmp = (u32 __user *) buf;
+ u32 data[2];
+ size_t rv;
+ u32 reg = *ppos;
+ int cpu = iminor(file->f_dentry->d_inode);
+ int err;
+
+ if (count % 8)
+ return -EINVAL; /* Invalid chunk size */
+
+ for (rv = 0; count; count -= 8) {
+ err = do_rdmsr(cpu, reg, &data[0], &data[1]);
+ if (err)
+ return err;
+ if (copy_to_user(tmp, &data, 8))
+ return -EFAULT;
+ tmp += 2;
+ }
+
+ return ((char __user *)tmp) - buf;
}
-static ssize_t msr_write(struct file * file, const char __user * buf,
+static ssize_t msr_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- const char __user *tmp = buf;
- u32 data[2];
- size_t rv;
- u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
- int err;
-
- if ( count % 8 )
- return -EINVAL; /* Invalid chunk size */
-
- for ( rv = 0 ; count ; count -= 8 ) {
- if ( copy_from_user(&data,tmp,8) )
- return -EFAULT;
- err = do_wrmsr(cpu, reg, data[0], data[1]);
- if ( err )
- return err;
- tmp += 8;
- }
-
- return tmp - buf;
+ const u32 __user *tmp = (const u32 __user *)buf;
+ u32 data[2];
+ size_t rv;
+ u32 reg = *ppos;
+ int cpu = iminor(file->f_dentry->d_inode);
+ int err;
+
+ if (count % 8)
+ return -EINVAL; /* Invalid chunk size */
+
+ for (rv = 0; count; count -= 8) {
+ if (copy_from_user(&data, tmp, 8))
+ return -EFAULT;
+ err = do_wrmsr(cpu, reg, data[0], data[1]);
+ if (err)
+ return err;
+ tmp += 2;
+ }
+
+ return ((char __user *)tmp) - buf;
}
static int msr_open(struct inode *inode, struct file *file)
{
- int cpu = iminor(file->f_dentry->d_inode);
- struct cpuinfo_x86 *c = &(cpu_data)[cpu];
-
- if (cpu >= NR_CPUS || !cpu_online(cpu))
- return -ENXIO; /* No such CPU */
- if ( !cpu_has(c, X86_FEATURE_MSR) )
- return -EIO; /* MSR not supported */
-
- return 0;
+ unsigned int cpu = iminor(file->f_dentry->d_inode);
+ struct cpuinfo_x86 *c = &(cpu_data)[cpu];
+
+ if (cpu >= NR_CPUS || !cpu_online(cpu))
+ return -ENXIO; /* No such CPU */
+ if (!cpu_has(c, X86_FEATURE_MSR))
+ return -EIO; /* MSR not supported */
+
+ return 0;
}
/*
* File operations we support
*/
static struct file_operations msr_fops = {
- .owner = THIS_MODULE,
- .llseek = msr_seek,
- .read = msr_read,
- .write = msr_write,
- .open = msr_open,
+ .owner = THIS_MODULE,
+ .llseek = msr_seek,
+ .read = msr_read,
+ .write = msr_write,
+ .open = msr_open,
};
int __init msr_init(void)
{
- if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
- printk(KERN_ERR "msr: unable to get major %d for msr\n",
- MSR_MAJOR);
- return -EBUSY;
- }
-
- return 0;
+ if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
+ printk(KERN_ERR "msr: unable to get major %d for msr\n",
+ MSR_MAJOR);
+ return -EBUSY;
+ }
+
+ return 0;
}
void __exit msr_exit(void)
{
- unregister_chrdev(MSR_MAJOR, "cpu/msr");
+ unregister_chrdev(MSR_MAJOR, "cpu/msr");
}
module_init(msr_init);
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index 7eb3fc72ae86c..cab471cf3edb3 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -1,5 +1,5 @@
/*
- * Dynamic DMA mapping support. Common code
+ * Dynamic DMA mapping support.
*/
#include <linux/types.h>
@@ -24,38 +24,37 @@
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
-int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
- int nents, int direction)
+int dma_map_sg(struct device *hwdev, struct scatterlist *sg,
+ int nents, int direction)
{
int i;
- BUG_ON(direction == PCI_DMA_NONE);
+ BUG_ON(direction == DMA_NONE);
for (i = 0; i < nents; i++ ) {
struct scatterlist *s = &sg[i];
BUG_ON(!s->page);
- s->dma_address = pci_map_page(hwdev, s->page, s->offset,
- s->length, direction);
+ s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
s->dma_length = s->length;
}
return nents;
}
-EXPORT_SYMBOL(pci_map_sg);
+EXPORT_SYMBOL(dma_map_sg);
/* Unmap a set of streaming mode DMA translations.
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
-void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg,
- int nents, int dir)
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, int dir)
{
int i;
for (i = 0; i < nents; i++) {
struct scatterlist *s = &sg[i];
BUG_ON(s->page == NULL);
BUG_ON(s->dma_address == 0);
- pci_unmap_single(dev, s->dma_address, s->dma_length, dir);
+ dma_unmap_single(dev, s->dma_address, s->dma_length, dir);
}
}
-EXPORT_SYMBOL(pci_unmap_sg);
+EXPORT_SYMBOL(dma_unmap_sg);
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 09fde74cba5bd..ca608a2a0aafc 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -31,12 +31,6 @@
#include <asm/cacheflush.h>
#include <asm/kdebug.h>
-#ifdef CONFIG_PREEMPT
-#define preempt_atomic() in_atomic()
-#else
-#define preempt_atomic() 1
-#endif
-
dma_addr_t bad_dma_address;
unsigned long iommu_bus_base; /* GART remapping area (physical) */
@@ -54,7 +48,7 @@ int force_iommu = 1;
int panic_on_overflow = 0;
int force_iommu = 0;
#endif
-int iommu_merge = 0;
+int iommu_merge = 1;
int iommu_sac_force = 0;
/* If this is disabled the IOMMU will use an optimized flushing strategy
@@ -64,6 +58,10 @@ int iommu_sac_force = 0;
also seen with Qlogic at least). */
int iommu_fullflush = 1;
+/* This tells the BIO block layer to assume merging. Default to off
+ because we cannot guarantee merging later. */
+int iommu_bio_merge = 0;
+
#define MAX_NB 8
/* Allocation bitmap for the remapping area */
@@ -104,8 +102,16 @@ AGPEXTERN __u32 *agp_gatt_table;
static unsigned long next_bit; /* protected by iommu_bitmap_lock */
static int need_flush; /* global flush state. set for each gart wrap */
-static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem,
- size_t size, int dir);
+static dma_addr_t dma_map_area(struct device *dev, unsigned long phys_mem,
+ size_t size, int dir, int do_panic);
+
+/* Dummy device used for NULL arguments (normally ISA). Better would
+ be probably a smaller DMA mask, but this is bug-to-bug compatible to i386. */
+static struct device fallback_dev = {
+ .bus_id = "fallback device",
+ .coherent_dma_mask = 0xffffffff,
+ .dma_mask = &fallback_dev.coherent_dma_mask,
+};
static unsigned long alloc_iommu(int size)
{
@@ -146,25 +152,31 @@ static void free_iommu(unsigned long offset, int size)
/*
* Use global flush state to avoid races with multiple flushers.
*/
-static void flush_gart(struct pci_dev *dev)
+static void flush_gart(struct device *dev)
{
unsigned long flags;
int flushed = 0;
- int i;
+ int i, max;
spin_lock_irqsave(&iommu_bitmap_lock, flags);
if (need_flush) {
+ max = 0;
for (i = 0; i < MAX_NB; i++) {
- u32 w;
if (!northbridges[i])
continue;
pci_write_config_dword(northbridges[i], 0x9c,
northbridge_flush_word[i] | 1);
+ flushed++;
+ max = i;
+ }
+ for (i = 0; i <= max; i++) {
+ u32 w;
+ if (!northbridges[i])
+ continue;
/* Make sure the hardware actually executed the flush. */
do {
pci_read_config_dword(northbridges[i], 0x9c, &w);
} while (w & 1);
- flushed++;
}
if (!flushed)
printk("nothing to flush?\n");
@@ -173,31 +185,47 @@ static void flush_gart(struct pci_dev *dev)
spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
}
+/* Allocate DMA memory on node near device */
+noinline
+static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order)
+{
+ struct page *page;
+ int node;
+ if (dev->bus == &pci_bus_type) {
+ cpumask_t mask;
+ mask = pcibus_to_cpumask(to_pci_dev(dev)->bus->number);
+ node = cpu_to_node(first_cpu(mask));
+ } else
+ node = numa_node_id();
+ page = alloc_pages_node(node, gfp, order);
+ return page ? page_address(page) : NULL;
+}
+
/*
- * Allocate memory for a consistent mapping.
+ * Allocate memory for a coherent mapping.
*/
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t *dma_handle)
+void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ unsigned gfp)
{
void *memory;
- int gfp = preempt_atomic() ? GFP_ATOMIC : GFP_KERNEL;
unsigned long dma_mask = 0;
u64 bus;
- if (hwdev)
- dma_mask = hwdev->dev.coherent_dma_mask;
+ if (!dev)
+ dev = &fallback_dev;
+ dma_mask = dev->coherent_dma_mask;
if (dma_mask == 0)
dma_mask = 0xffffffff;
/* Kludge to make it bug-to-bug compatible with i386. i386
- uses the normal dma_mask for alloc_consistent. */
- if (hwdev)
- dma_mask &= hwdev->dma_mask;
+ uses the normal dma_mask for alloc_coherent. */
+ dma_mask &= *dev->dma_mask;
again:
- memory = (void *)__get_free_pages(gfp, get_order(size));
+ memory = dma_alloc_pages(dev, gfp, get_order(size));
if (memory == NULL)
- return NULL;
+ return NULL;
{
int high, mmu;
@@ -223,28 +251,29 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
}
}
- *dma_handle = pci_map_area(hwdev, bus, size, PCI_DMA_BIDIRECTIONAL);
+ *dma_handle = dma_map_area(dev, bus, size, PCI_DMA_BIDIRECTIONAL, 0);
if (*dma_handle == bad_dma_address)
goto error;
- flush_gart(hwdev);
+ flush_gart(dev);
return memory;
error:
if (panic_on_overflow)
- panic("pci_alloc_consistent: overflow %lu bytes\n", size);
+ panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n", size);
free:
free_pages((unsigned long)memory, get_order(size));
+ /* XXX Could use the swiotlb pool here too */
return NULL;
}
/*
- * Unmap consistent memory.
+ * Unmap coherent memory.
* The caller must ensure that the device has finished accessing the mapping.
*/
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t bus)
{
- pci_unmap_single(hwdev, bus, size, 0);
+ dma_unmap_single(dev, bus, size, 0);
free_pages((unsigned long)vaddr, get_order(size));
}
@@ -280,7 +309,7 @@ void dump_leak(void)
#define CLEAR_LEAK(x)
#endif
-static void iommu_full(struct pci_dev *dev, size_t size, int dir)
+static void iommu_full(struct device *dev, size_t size, int dir, int do_panic)
{
/*
* Ran out of IOMMU space for this operation. This is very bad.
@@ -293,14 +322,14 @@ static void iommu_full(struct pci_dev *dev, size_t size, int dir)
*/
printk(KERN_ERR
- "PCI-DMA: Out of IOMMU space for %lu bytes at device %s[%s]\n",
- size, dev ? pci_pretty_name(dev) : "", dev ? dev->slot_name : "?");
+ "PCI-DMA: Out of IOMMU space for %lu bytes at device %s\n",
+ size, dev->bus_id);
- if (size > PAGE_SIZE*EMERGENCY_PAGES) {
+ if (size > PAGE_SIZE*EMERGENCY_PAGES && do_panic) {
if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
- panic("PCI-DMA: Memory will be corrupted\n");
+ panic("PCI-DMA: Memory would be corrupted\n");
if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL)
- panic("PCI-DMA: Random memory will be DMAed\n");
+ panic("PCI-DMA: Random memory would be DMAed\n");
}
#ifdef CONFIG_IOMMU_LEAK
@@ -308,9 +337,9 @@ static void iommu_full(struct pci_dev *dev, size_t size, int dir)
#endif
}
-static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t size)
+static inline int need_iommu(struct device *dev, unsigned long addr, size_t size)
{
- u64 mask = dev ? dev->dma_mask : 0xffffffff;
+ u64 mask = *dev->dma_mask;
int high = addr + size >= mask;
int mmu = high;
if (force_iommu)
@@ -323,9 +352,9 @@ static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t siz
return mmu;
}
-static inline int nonforced_iommu(struct pci_dev *dev, unsigned long addr, size_t size)
+static inline int nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
{
- u64 mask = dev ? dev->dma_mask : 0xffffffff;
+ u64 mask = *dev->dma_mask;
int high = addr + size >= mask;
int mmu = high;
if (no_iommu) {
@@ -339,8 +368,8 @@ static inline int nonforced_iommu(struct pci_dev *dev, unsigned long addr, size_
/* Map a single continuous physical area into the IOMMU.
* Caller needs to check if the iommu is needed and flush.
*/
-static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem,
- size_t size, int dir)
+static dma_addr_t dma_map_area(struct device *dev, unsigned long phys_mem,
+ size_t size, int dir, int do_panic)
{
unsigned long npages = to_pages(phys_mem, size);
unsigned long iommu_page = alloc_iommu(npages);
@@ -349,8 +378,8 @@ static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem,
if (!nonforced_iommu(dev, phys_mem, size))
return phys_mem;
if (panic_on_overflow)
- panic("pci_map_area overflow %lu bytes\n", size);
- iommu_full(dev, size, dir);
+ panic("dma_map_area overflow %lu bytes\n", size);
+ iommu_full(dev, size, dir, do_panic);
return bad_dma_address;
}
@@ -363,44 +392,44 @@ static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem,
}
/* Map a single area into the IOMMU */
-dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size, int dir)
-{
+dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size, int dir)
+{
unsigned long phys_mem, bus;
- BUG_ON(dir == PCI_DMA_NONE);
+ BUG_ON(dir == DMA_NONE);
-#ifdef CONFIG_SWIOTLB
if (swiotlb)
- return swiotlb_map_single(&dev->dev,addr,size,dir);
-#endif
+ return swiotlb_map_single(dev,addr,size,dir);
+ if (!dev)
+ dev = &fallback_dev;
phys_mem = virt_to_phys(addr);
if (!need_iommu(dev, phys_mem, size))
return phys_mem;
- bus = pci_map_area(dev, phys_mem, size, dir);
+ bus = dma_map_area(dev, phys_mem, size, dir, 1);
flush_gart(dev);
return bus;
}
-/* Fallback for pci_map_sg in case of overflow */
-static int pci_map_sg_nonforce(struct pci_dev *dev, struct scatterlist *sg,
+/* Fallback for dma_map_sg in case of overflow */
+static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
int nents, int dir)
{
int i;
#ifdef CONFIG_IOMMU_DEBUG
- printk(KERN_DEBUG "pci_map_sg overflow\n");
+ printk(KERN_DEBUG "dma_map_sg overflow\n");
#endif
for (i = 0; i < nents; i++ ) {
struct scatterlist *s = &sg[i];
unsigned long addr = page_to_phys(s->page) + s->offset;
if (nonforced_iommu(dev, addr, s->length)) {
- addr = pci_map_area(dev, addr, s->length, dir);
+ addr = dma_map_area(dev, addr, s->length, dir, 0);
if (addr == bad_dma_address) {
if (i > 0)
- pci_unmap_sg(dev, sg, i, dir);
+ dma_unmap_sg(dev, sg, i, dir);
nents = 0;
sg[0].dma_length = 0;
break;
@@ -414,7 +443,7 @@ static int pci_map_sg_nonforce(struct pci_dev *dev, struct scatterlist *sg,
}
/* Map multiple scatterlist entries continuous into the first. */
-static int __pci_map_cont(struct scatterlist *sg, int start, int stopat,
+static int __dma_map_cont(struct scatterlist *sg, int start, int stopat,
struct scatterlist *sout, unsigned long pages)
{
unsigned long iommu_start = alloc_iommu(pages);
@@ -452,7 +481,7 @@ static int __pci_map_cont(struct scatterlist *sg, int start, int stopat,
return 0;
}
-static inline int pci_map_cont(struct scatterlist *sg, int start, int stopat,
+static inline int dma_map_cont(struct scatterlist *sg, int start, int stopat,
struct scatterlist *sout,
unsigned long pages, int need)
{
@@ -462,14 +491,14 @@ static inline int pci_map_cont(struct scatterlist *sg, int start, int stopat,
sout->dma_length = sg[start].length;
return 0;
}
- return __pci_map_cont(sg, start, stopat, sout, pages);
+ return __dma_map_cont(sg, start, stopat, sout, pages);
}
/*
* DMA map all entries in a scatterlist.
* Merge chunks that have page aligned sizes into a continuous mapping.
- */
-int pci_map_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int dir)
+ */
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
{
int i;
int out;
@@ -477,19 +506,14 @@ int pci_map_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int dir)
unsigned long pages = 0;
int need = 0, nextneed;
-#ifdef CONFIG_SWIOTLB
- if (swiotlb)
- return swiotlb_map_sg(&dev->dev,sg,nents,dir);
-#endif
-
- BUG_ON(dir == PCI_DMA_NONE);
+ BUG_ON(dir == DMA_NONE);
if (nents == 0)
return 0;
-#ifdef CONFIG_SWIOTLB
if (swiotlb)
- return swiotlb_map_sg(&dev->dev,sg,nents,dir);
-#endif
+ return swiotlb_map_sg(dev,sg,nents,dir);
+ if (!dev)
+ dev = &fallback_dev;
out = 0;
start = 0;
@@ -508,19 +532,19 @@ int pci_map_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int dir)
boundary and the new one doesn't have an offset. */
if (!iommu_merge || !nextneed || !need || s->offset ||
(ps->offset + ps->length) % PAGE_SIZE) {
- if (pci_map_cont(sg, start, i, sg+out, pages,
+ if (dma_map_cont(sg, start, i, sg+out, pages,
need) < 0)
goto error;
out++;
pages = 0;
start = i;
}
- }
+ }
need = nextneed;
pages += to_pages(s->offset, s->length);
}
- if (pci_map_cont(sg, start, i, sg+out, pages, need) < 0)
+ if (dma_map_cont(sg, start, i, sg+out, pages, need) < 0)
goto error;
out++;
flush_gart(dev);
@@ -530,34 +554,32 @@ int pci_map_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int dir)
error:
flush_gart(NULL);
- pci_unmap_sg(dev, sg, nents, dir);
+ dma_unmap_sg(dev, sg, nents, dir);
/* When it was forced try again unforced */
if (force_iommu)
- return pci_map_sg_nonforce(dev, sg, nents, dir);
+ return dma_map_sg_nonforce(dev, sg, nents, dir);
if (panic_on_overflow)
- panic("pci_map_sg: overflow on %lu pages\n", pages);
- iommu_full(dev, pages << PAGE_SHIFT, dir);
+ panic("dma_map_sg: overflow on %lu pages\n", pages);
+ iommu_full(dev, pages << PAGE_SHIFT, dir, 0);
for (i = 0; i < nents; i++)
sg[i].dma_address = bad_dma_address;
return 0;
}
/*
- * Free a PCI mapping.
+ * Free a DMA mapping.
*/
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
size_t size, int direction)
{
unsigned long iommu_page;
int npages;
int i;
-#ifdef CONFIG_SWIOTLB
if (swiotlb) {
- swiotlb_unmap_single(&hwdev->dev,dma_addr,size,direction);
+ swiotlb_unmap_single(dev,dma_addr,size,direction);
return;
}
-#endif
if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE ||
dma_addr >= iommu_bus_base + iommu_size)
@@ -574,22 +596,25 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
/*
* Wrapper for pci_unmap_single working with scatterlists.
*/
-void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg, int nents,
- int dir)
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
{
int i;
+ if (swiotlb) {
+ swiotlb_unmap_sg(dev,sg,nents,dir);
+ return;
+ }
for (i = 0; i < nents; i++) {
struct scatterlist *s = &sg[i];
if (!s->dma_length || !s->length)
break;
- pci_unmap_single(dev, s->dma_address, s->dma_length, dir);
+ dma_unmap_single(dev, s->dma_address, s->dma_length, dir);
}
}
-int pci_dma_supported(struct pci_dev *dev, u64 mask)
+int dma_supported(struct device *dev, u64 mask)
{
/* Copied from i386. Doesn't make much sense, because it will
- only work for pci_alloc_consistent.
+ only work for pci_alloc_coherent.
The caller just has to use GFP_DMA in this case. */
if (mask < 0x00ffffff)
return 0;
@@ -605,22 +630,31 @@ int pci_dma_supported(struct pci_dev *dev, u64 mask)
Assume all masks <= 40 bits are of this type. Normally this doesn't
make any difference, but gives more gentle handling of IOMMU overflow. */
if (iommu_sac_force && (mask >= 0xffffffffffULL)) {
- printk(KERN_INFO "%s: Force SAC with mask %Lx\n", dev->slot_name,mask);
+ printk(KERN_INFO "%s: Force SAC with mask %Lx\n", dev->bus_id,mask);
return 0;
}
return 1;
}
-EXPORT_SYMBOL(pci_unmap_sg);
-EXPORT_SYMBOL(pci_map_sg);
-EXPORT_SYMBOL(pci_map_single);
-EXPORT_SYMBOL(pci_unmap_single);
-EXPORT_SYMBOL(pci_dma_supported);
+int dma_get_cache_alignment(void)
+{
+ return boot_cpu_data.x86_clflush_size;
+}
+
+EXPORT_SYMBOL(dma_unmap_sg);
+EXPORT_SYMBOL(dma_map_sg);
+EXPORT_SYMBOL(dma_map_single);
+EXPORT_SYMBOL(dma_unmap_single);
+EXPORT_SYMBOL(dma_supported);
EXPORT_SYMBOL(no_iommu);
EXPORT_SYMBOL(force_iommu);
EXPORT_SYMBOL(bad_dma_address);
-EXPORT_SYMBOL(iommu_merge);
+EXPORT_SYMBOL(iommu_bio_merge);
+EXPORT_SYMBOL(iommu_sac_force);
+EXPORT_SYMBOL(dma_get_cache_alignment);
+EXPORT_SYMBOL(dma_alloc_coherent);
+EXPORT_SYMBOL(dma_free_coherent);
static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
{
@@ -747,7 +781,7 @@ static int __init pci_iommu_init(void)
if (swiotlb) {
no_iommu = 1;
- printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n");
+ printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n");
return -1;
}
@@ -851,7 +885,7 @@ static int __init pci_iommu_init(void)
fs_initcall(pci_iommu_init);
/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,merge]
- [,forcesac][,fullflush][,nomerge]
+ [,forcesac][,fullflush][,nomerge][,biomerge]
size set size of iommu (in bytes)
noagp don't initialize the AGP driver and use full aperture.
off don't use the IOMMU
@@ -859,60 +893,73 @@ fs_initcall(pci_iommu_init);
memaper[=order] allocate an own aperture over RAM with size 32MB^order.
noforce don't force IOMMU usage. Default.
force Force IOMMU.
- merge Do SG merging. Implies force (experimental)
+ merge Do lazy merging. This may improve performance on some block devices.
+ Implies force (experimental)
+ biomerge Do merging at the BIO layer. This is more efficient than merge,
+ but should be only done with very big IOMMUs. Implies merge,force.
nomerge Don't do SG merging.
forcesac For SAC mode for masks <40bits (experimental)
fullflush Flush IOMMU on each allocation (default)
nofullflush Don't use IOMMU fullflush
allowed overwrite iommu off workarounds for specific chipsets.
soft Use software bounce buffering (default for Intel machines)
+ noaperture Don't touch the aperture for AGP.
*/
-__init int iommu_setup(char *opt)
+__init int iommu_setup(char *p)
{
int arg;
- char *p = opt;
-
- for (;;) {
- if (!memcmp(p,"noagp", 5))
+
+ while (*p) {
+ if (!strncmp(p,"noagp",5))
no_agp = 1;
- if (!memcmp(p,"off", 3))
+ if (!strncmp(p,"off",3))
no_iommu = 1;
- if (!memcmp(p,"force", 5)) {
+ if (!strncmp(p,"force",5)) {
force_iommu = 1;
iommu_aperture_allowed = 1;
}
- if (!memcmp(p,"allowed",7))
+ if (!strncmp(p,"allowed",7))
iommu_aperture_allowed = 1;
- if (!memcmp(p,"noforce", 7)) {
+ if (!strncmp(p,"noforce",7)) {
iommu_merge = 0;
force_iommu = 0;
}
- if (!memcmp(p, "memaper", 7)) {
+ if (!strncmp(p, "memaper", 7)) {
fallback_aper_force = 1;
p += 7;
- if (*p == '=' && get_option(&p, &arg))
- fallback_aper_order = arg;
+ if (*p == '=') {
+ ++p;
+ if (get_option(&p, &arg))
+ fallback_aper_order = arg;
+ }
}
- if (!memcmp(p, "panic", 5))
+ if (!strncmp(p, "biomerge",8)) {
+ iommu_bio_merge = 4096;
+ iommu_merge = 1;
+ force_iommu = 1;
+ }
+ if (!strncmp(p, "panic",5))
panic_on_overflow = 1;
- if (!memcmp(p, "nopanic", 7))
+ if (!strncmp(p, "nopanic",7))
panic_on_overflow = 0;
- if (!memcmp(p, "merge", 5)) {
+ if (!strncmp(p, "merge",5)) {
iommu_merge = 1;
force_iommu = 1;
}
- if (!memcmp(p, "nomerge", 7))
+ if (!strncmp(p, "nomerge",7))
iommu_merge = 0;
- if (!memcmp(p, "forcesac", 8))
+ if (!strncmp(p, "forcesac",8))
iommu_sac_force = 1;
- if (!memcmp(p, "fullflush", 9))
+ if (!strncmp(p, "fullflush",8))
iommu_fullflush = 1;
- if (!memcmp(p, "nofullflush", 11))
+ if (!strncmp(p, "nofullflush",11))
iommu_fullflush = 0;
- if (!memcmp(p, "soft", 4))
+ if (!strncmp(p, "soft",4))
swiotlb = 1;
+ if (!strncmp(p, "noaperture",10))
+ fix_aperture = 0;
#ifdef CONFIG_IOMMU_LEAK
- if (!memcmp(p,"leak", 4)) {
+ if (!strncmp(p,"leak",4)) {
leak_trace = 1;
p += 4;
if (*p == '=') ++p;
@@ -922,10 +969,9 @@ __init int iommu_setup(char *opt)
#endif
if (isdigit(*p) && get_option(&p, &arg))
iommu_size = arg;
- do {
- if (*p == ' ' || *p == 0)
- return 0;
- } while (*p++ != ',');
+ p += strcspn(p, ",");
+ if (*p == ',')
+ ++p;
}
return 1;
}
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index 00fb2645c510a..67d90b89af0b0 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -1,8 +1,11 @@
+/* Fallback functions when the main IOMMU code is not compiled in. This
+ code is roughly equivalent to i386. */
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <asm/proto.h>
+#include <asm/processor.h>
int iommu_merge = 0;
EXPORT_SYMBOL(iommu_merge);
@@ -10,57 +13,80 @@ EXPORT_SYMBOL(iommu_merge);
dma_addr_t bad_dma_address;
EXPORT_SYMBOL(bad_dma_address);
+int iommu_bio_merge = 0;
+EXPORT_SYMBOL(iommu_bio_merge);
+
+int iommu_sac_force = 0;
+EXPORT_SYMBOL(iommu_sac_force);
+
/*
* Dummy IO MMU functions
*/
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t *dma_handle)
+void *dma_alloc_coherent(struct device *hwdev, size_t size,
+ dma_addr_t *dma_handle, unsigned gfp)
{
void *ret;
- int gfp = GFP_ATOMIC;
-
- if (hwdev == NULL ||
- end_pfn > (hwdev->dma_mask>>PAGE_SHIFT) || /* XXX */
- (u32)hwdev->dma_mask < 0xffffffff)
- gfp |= GFP_DMA;
- ret = (void *)__get_free_pages(gfp, get_order(size));
+ u64 mask;
+ int order = get_order(size);
- if (ret != NULL) {
- memset(ret, 0, size);
+ if (hwdev)
+ mask = hwdev->coherent_dma_mask & *hwdev->dma_mask;
+ else
+ mask = 0xffffffff;
+ for (;;) {
+ ret = (void *)__get_free_pages(gfp, order);
+ if (ret == NULL)
+ return NULL;
*dma_handle = virt_to_bus(ret);
+ if ((*dma_handle & ~mask) == 0)
+ break;
+ free_pages((unsigned long)ret, order);
+ if (gfp & GFP_DMA)
+ return NULL;
+ gfp |= GFP_DMA;
}
+
+ memset(ret, 0, size);
return ret;
}
+EXPORT_SYMBOL(dma_alloc_coherent);
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+void dma_free_coherent(struct device *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
free_pages((unsigned long)vaddr, get_order(size));
}
+EXPORT_SYMBOL(dma_free_coherent);
-int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
+int dma_supported(struct device *hwdev, u64 mask)
{
/*
* we fall back to GFP_DMA when the mask isn't all 1s,
* so we can't guarantee allocations that must be
* within a tighter range than GFP_DMA..
- * RED-PEN this won't work for pci_map_single. Caller has to
- * use GFP_DMA in the first place.
+ * RED-PEN this won't work for pci_map_single. Caller has to
+ * use GFP_DMA in the first place.
*/
if (mask < 0x00ffffff)
return 0;
return 1;
}
+EXPORT_SYMBOL(dma_supported);
-EXPORT_SYMBOL(pci_dma_supported);
+int dma_get_cache_alignment(void)
+{
+ return boot_cpu_data.x86_clflush_size;
+}
+EXPORT_SYMBOL(dma_get_cache_alignment);
static int __init check_ram(void)
{
if (end_pfn >= 0xffffffff>>PAGE_SHIFT) {
- printk(KERN_ERR "WARNING more than 4GB of memory but no IOMMU.\n"
- KERN_ERR "WARNING 32bit PCI may malfunction.\n");
+ printk(
+ KERN_ERR "WARNING more than 4GB of memory but IOMMU not compiled in.\n"
+ KERN_ERR "WARNING 32bit PCI may malfunction.\n");
}
return 0;
}
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index f7d3cf3cac4c0..9510c46a75466 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -168,9 +168,7 @@ void __init select_idle_routine(const struct cpuinfo_x86 *c)
if (cpu_has(c, X86_FEATURE_MWAIT)) {
/*
* Skip, if setup has overridden idle.
- * Also, take care of system with asymmetric CPUs.
- * Use, mwait_idle only if all cpus support it.
- * If not, we fallback to default_idle()
+ * One CPU supports mwait => All CPUs supports mwait
*/
if (!pm_idle) {
if (!printed) {
@@ -179,10 +177,7 @@ void __init select_idle_routine(const struct cpuinfo_x86 *c)
}
pm_idle = mwait_idle;
}
- return;
}
- pm_idle = default_idle;
- return;
}
static int __init idle_setup (char *str)
@@ -546,17 +541,16 @@ void set_personality_64bit(void)
clear_thread_flag(TIF_IA32);
}
-asmlinkage long sys_fork(struct pt_regs regs)
+asmlinkage long sys_fork(struct pt_regs *regs)
{
- return do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL, NULL);
+ return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL);
}
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs regs)
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
{
if (!newsp)
- newsp = regs.rsp;
- return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0,
- parent_tid, child_tid);
+ newsp = regs->rsp;
+ return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
/*
@@ -569,9 +563,9 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void _
* do not have enough call-clobbered registers to hold all
* the information you need.
*/
-asmlinkage long sys_vfork(struct pt_regs regs)
+asmlinkage long sys_vfork(struct pt_regs *regs)
{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0,
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0,
NULL, NULL);
}
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 8e3431564f253..73ff5494a6c15 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -433,30 +433,32 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
break;
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
- if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, FRAME_SIZE)) {
+ if (!access_ok(VERIFY_WRITE, (unsigned __user *)data,
+ sizeof(struct user_regs_struct))) {
ret = -EIO;
break;
}
+ ret = 0;
for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) {
- __put_user(getreg(child, ui),(unsigned long __user *) data);
+ ret |= __put_user(getreg(child, ui),(unsigned long __user *) data);
data += sizeof(long);
}
- ret = 0;
break;
}
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
unsigned long tmp;
- if (!access_ok(VERIFY_READ, (unsigned __user *)data, FRAME_SIZE)) {
+ if (!access_ok(VERIFY_READ, (unsigned __user *)data,
+ sizeof(struct user_regs_struct))) {
ret = -EIO;
break;
}
+ ret = 0;
for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) {
- __get_user(tmp, (unsigned long __user *) data);
+ ret |= __get_user(tmp, (unsigned long __user *) data);
putreg(child, ui, tmp);
data += sizeof(long);
}
- ret = 0;
break;
}
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index d4e3cfef90421..24b2f7806d06d 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -79,8 +79,10 @@ unsigned long pci_mem_start = 0x10000000;
unsigned long saved_video_mode;
+#ifdef CONFIG_SWIOTLB
int swiotlb;
EXPORT_SYMBOL(swiotlb);
+#endif
/*
* Setup options
@@ -765,6 +767,7 @@ static struct _cache_table cache_table[] __initdata =
{ 0x43, LVL_2, 512 },
{ 0x44, LVL_2, 1024 },
{ 0x45, LVL_2, 2048 },
+ { 0x60, LVL_1_DATA, 16 },
{ 0x66, LVL_1_DATA, 8 },
{ 0x67, LVL_1_DATA, 16 },
{ 0x68, LVL_1_DATA, 32 },
@@ -1059,8 +1062,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Intel-defined (#2) */
- "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2",
- "est", NULL, "cid", NULL, NULL, "cmpxchg16b", NULL, NULL,
+ "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est",
+ "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 9d3137a553fff..808fbb4230ccf 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -60,12 +60,12 @@ noforce (default) Don't enable by default for heap/stack/data,
*/
static int __init nonx_setup(char *str)
{
- if (!strncmp(str, "on",3)) {
+ if (!strcmp(str, "on")) {
__supported_pte_mask |= _PAGE_NX;
do_not_nx = 0;
vm_data_default_flags &= ~VM_EXEC;
vm_stack_flags &= ~VM_EXEC;
- } else if (!strncmp(str, "noforce",7) || !strncmp(str,"off",3)) {
+ } else if (!strcmp(str, "noforce") || !strcmp(str, "off")) {
do_not_nx = (str[0] == 'o');
if (do_not_nx)
__supported_pte_mask &= ~_PAGE_NX;
@@ -91,26 +91,28 @@ Valid options:
compat (default) Imply PROT_EXEC for PROT_READ
*/
- static int __init nonx32_setup(char *str)
+ static int __init nonx32_setup(char *s)
{
- char *s;
- while ((s = strsep(&str, ",")) != NULL) {
- if (!strcmp(s, "all") || !strcmp(s,"on")) {
+ while (*s) {
+ if (!strncmp(s, "all", 3) || !strncmp(s,"on",2)) {
vm_data_default_flags32 &= ~VM_EXEC;
vm_stack_flags32 &= ~VM_EXEC;
- } else if (!strcmp(s, "off")) {
+ } else if (!strncmp(s, "off",3)) {
vm_data_default_flags32 |= VM_EXEC;
vm_stack_flags32 |= VM_EXEC;
- } else if (!strcmp(s, "stack")) {
+ } else if (!strncmp(s, "stack", 5)) {
vm_data_default_flags32 |= VM_EXEC;
vm_stack_flags32 &= ~VM_EXEC;
- } else if (!strcmp(s, "force")) {
+ } else if (!strncmp(s, "force",5)) {
vm_force_exec32 = 0;
- } else if (!strcmp(s, "compat")) {
+ } else if (!strncmp(s, "compat",5)) {
vm_force_exec32 = PROT_EXEC;
}
- }
- return 1;
+ s += strcspn(s, ",");
+ if (*s == ',')
+ ++s;
+ }
+ return 1;
}
__setup("noexec32=", nonx32_setup);
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index f6eb0e337f6f5..978fae2a9ca8c 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -40,7 +40,7 @@ void ia32_setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs);
asmlinkage long
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs regs)
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
{
sigset_t saveset, newset;
@@ -59,21 +59,22 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs re
spin_unlock_irq(&current->sighand->siglock);
#ifdef DEBUG_SIG
printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
- saveset, newset, &regs, regs.rip);
+ saveset, newset, regs, regs->rip);
#endif
- regs.rax = -EINTR;
+ regs->rax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&regs, &saveset))
+ if (do_signal(regs, &saveset))
return -EINTR;
}
}
asmlinkage long
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs regs)
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+ struct pt_regs *regs)
{
- return do_sigaltstack(uss, uoss, regs.rsp);
+ return do_sigaltstack(uss, uoss, regs->rsp);
}
@@ -134,13 +135,13 @@ badframe:
return 1;
}
-asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
sigset_t set;
long eax;
- frame = (struct rt_sigframe __user *)(regs.rsp - 8);
+ frame = (struct rt_sigframe __user *)(regs->rsp - 8);
if (verify_area(VERIFY_READ, frame, sizeof(*frame))) {
goto badframe;
}
@@ -154,7 +155,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax)) {
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) {
goto badframe;
}
@@ -162,13 +163,13 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs regs)
printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
#endif
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs.rsp) == -EFAULT)
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT)
goto badframe;
return eax;
badframe:
- signal_fault(&regs,frame,"sigreturn");
+ signal_fault(regs,frame,"sigreturn");
return 0;
}
@@ -287,7 +288,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (ka->sa.sa_flags & SA_RESTORER) {
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
} else {
- printk("%s forgot to set SA_RESTORER for signal %d.\n", me->comm, sig);
+ /* could use a vstub here */
goto give_sigsegv;
}
@@ -328,9 +329,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- signal_fault(regs,frame,"signal deliver");
+ force_sigsegv(sig, current);
}
/*
@@ -338,11 +337,9 @@ give_sigsegv:
*/
static void
-handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
- struct pt_regs * regs)
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+ sigset_t *oldset, struct pt_regs *regs)
{
- struct k_sigaction *ka = &current->sighand->action[sig-1];
-
#ifdef DEBUG_SIG
printk("handle_signal pid:%d sig:%lu rip:%lx rsp:%lx regs=%p\n", current->pid, sig,
regs->rip, regs->rsp, regs);
@@ -379,9 +376,6 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
#endif
setup_rt_frame(sig, ka, info, oldset, regs);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -398,6 +392,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
*/
int do_signal(struct pt_regs *regs, sigset_t *oldset)
{
+ struct k_sigaction ka;
siginfo_t info;
int signr;
@@ -419,7 +414,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!oldset)
oldset = &current->blocked;
- signr = get_signal_to_deliver(&info, regs, NULL);
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Reenable any watchpoints before delivering the
* signal to user space. The processor register will
@@ -430,7 +425,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
asm volatile("movq %0,%%db7" : : "r" (current->thread.debugreg7));
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &info, oldset, regs);
+ handle_signal(signr, &info, &ka, oldset, regs);
return 1;
}
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index af49e0ccd5483..5cc75bb45a5d9 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -392,16 +392,6 @@ void __init start_secondary(void)
extern volatile unsigned long init_rsp;
extern void (*initial_code)(void);
-static struct task_struct * __init fork_by_hand(void)
-{
- struct pt_regs regs;
- /*
- * don't care about the eip and regs settings since
- * we'll never reschedule the forked task.
- */
- return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
-}
-
#if APIC_DEBUG
static inline void inquire_remote_apic(int apicid)
{
@@ -575,20 +565,11 @@ static void __init do_boot_cpu (int apicid)
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
- idle = fork_by_hand();
+ idle = fork_idle(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
- wake_up_forked_process(idle);
x86_cpu_to_apicid[cpu] = apicid;
- /*
- * We remove it from the pidhash and the runqueue
- * once we got the process:
- */
- init_idle(idle,cpu);
-
- unhash_process(idle);
-
cpu_pda[cpu].pcurrent = idle;
start_rip = setup_trampoline();
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 10c511f50d1df..bca41293aca7c 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -11,7 +11,6 @@
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 2003 Andi Kleen
* RTC support code taken from arch/i386/kernel/timers/time_hpet.c
- *
*/
#include <linux/kernel.h>
@@ -42,6 +41,10 @@ u64 jiffies_64 = INITIAL_JIFFIES;
EXPORT_SYMBOL(jiffies_64);
+#ifdef CONFIG_CPU_FREQ
+static void cpufreq_delayed_get(void);
+#endif
+
extern int using_apic_timer;
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
@@ -82,7 +85,7 @@ static inline void rdtscll_sync(unsigned long *tsc)
* timer interrupt has happened already, but vxtime.trigger wasn't updated yet.
* This is not a problem, because jiffies hasn't updated either. They are bound
* together by xtime_lock.
- */
+ */
static inline unsigned int do_gettimeoffset_tsc(void)
{
@@ -119,7 +122,7 @@ void do_gettimeofday(struct timeval *tv)
usec = xtime.tv_nsec / 1000;
/* i386 does some correction here to keep the clock
- monotonus even when ntpd is fixing drift.
+ monotonous even when ntpd is fixing drift.
But they didn't work for me, there is a non monotonic
clock anyways with ntp.
I dropped all corrections now until a real solution can
@@ -214,7 +217,7 @@ static void set_rtc_mmss(unsigned long nowtime)
* overflow. This avoids messing with unknown time zones but requires your RTC
* not to be off by more than 15 minutes. Since we're calling it only when
* our clock is externally synchronized using NTP, this shouldn't be a problem.
- */
+ */
real_seconds = nowtime % 60;
real_minutes = nowtime / 60;
@@ -297,15 +300,15 @@ EXPORT_SYMBOL(monotonic_clock);
static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
static unsigned long rtc_update = 0;
- unsigned long tsc, lost = 0;
- int delay, offset = 0;
+ unsigned long tsc;
+ int delay, offset = 0, lost = 0;
/*
* Here we are in the timer irq handler. We have irqs locally disabled (so we
* don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
* on the other CPU, so we need a lock. We also need to lock the vsyscall
* variables, because both do_timer() and us change them -arca+vojtech
- */
+ */
write_seqlock(&xtime_lock);
@@ -354,12 +357,29 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
(((long) offset << 32) / vxtime.tsc_quot) - 1;
}
- if (lost) {
+ if (lost > 0) {
+ static long lost_count;
+
if (report_lost_ticks) {
- printk(KERN_WARNING "time.c: Lost %ld timer "
+ printk(KERN_WARNING "time.c: Lost %d timer "
"tick(s)! ", lost);
print_symbol("rip %s)\n", regs->rip);
}
+
+ if (lost_count == 100) {
+ printk(KERN_WARNING
+ "warning: many lost ticks.\n"
+ KERN_WARNING "Your time source seems to be instable or some driver is hogging interupts\n");
+ print_symbol("rip %s\n", regs->rip);
+ lost_count = 0;
+ } else
+ lost_count++;
+
+ if ((lost_count % 25) == 0) {
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_delayed_get();
+#endif
+ }
jiffies += lost;
}
@@ -509,6 +529,34 @@ unsigned long get_cmos_time(void)
Should fix up last_tsc too. Currently gettimeofday in the
first tick after the change will be slightly wrong. */
+#include <linux/workqueue.h>
+
+static unsigned int cpufreq_delayed_issched = 0;
+static unsigned int cpufreq_init = 0;
+static struct work_struct cpufreq_delayed_get_work;
+
+static void handle_cpufreq_delayed_get(void *v)
+{
+ unsigned int cpu;
+ for_each_online_cpu(cpu) {
+ cpufreq_get(cpu);
+ }
+ cpufreq_delayed_issched = 0;
+}
+
+/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries
+ * to verify the CPU frequency the timing core thinks the CPU is running
+ * at is still correct.
+ */
+static void cpufreq_delayed_get(void)
+{
+ if (cpufreq_init && !cpufreq_delayed_issched) {
+ cpufreq_delayed_issched = 1;
+ printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n");
+ schedule_work(&cpufreq_delayed_get_work);
+ }
+}
+
static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0;
@@ -518,14 +566,18 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_freqs *freq = data;
- unsigned long *lpj;
+ unsigned long *lpj, dummy;
+ lpj = &dummy;
+ if (!(freq->flags & CPUFREQ_CONST_LOOPS))
#ifdef CONFIG_SMP
lpj = &cpu_data[freq->cpu].loops_per_jiffy;
#else
lpj = &boot_cpu_data.loops_per_jiffy;
#endif
+
+
if (!ref_freq) {
ref_freq = freq->old;
loops_per_jiffy_ref = *lpj;
@@ -538,7 +590,8 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
- vxtime.tsc_quot = (1000L << 32) / cpu_khz;
+ if (!(freq->flags & CPUFREQ_CONST_LOOPS))
+ vxtime.tsc_quot = (1000L << 32) / cpu_khz;
}
set_cyc2ns_scale(cpu_khz_ref / 1000);
@@ -549,6 +602,18 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
static struct notifier_block time_cpufreq_notifier_block = {
.notifier_call = time_cpufreq_notifier
};
+
+static int __init cpufreq_tsc(void)
+{
+ INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
+ if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER))
+ cpufreq_init = 1;
+ return 0;
+}
+
+core_initcall(cpufreq_tsc);
+
#endif
/*
@@ -725,8 +790,8 @@ void __init time_init(void)
cpu_khz = hpet_calibrate_tsc();
timename = "HPET";
} else {
- pit_init();
- cpu_khz = pit_calibrate_tsc();
+ pit_init();
+ cpu_khz = pit_calibrate_tsc();
timename = "PIT";
}
@@ -742,11 +807,6 @@ void __init time_init(void)
setup_irq(0, &irq0);
set_cyc2ns_scale(cpu_khz / 1000);
-
-#ifdef CONFIG_CPU_FREQ
- cpufreq_register_notifier(&time_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-#endif
}
void __init time_init_smp(void)
@@ -1038,6 +1098,8 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
#endif
+
+
static int __init nohpet_setup(char *s)
{
nohpet = 1;
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 99d0ec2abd006..5d3563033798f 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -352,7 +352,7 @@ void __die(const char * str, struct pt_regs * regs, long err)
#ifdef CONFIG_DEBUG_PAGEALLOC
printk("DEBUG_PAGEALLOC");
#endif
- printk("\n");
+ printk("\n");
notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
show_registers(regs);
/* Executive summary in case the oops scrolled away */
@@ -513,7 +513,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 13;
force_sig(SIGSEGV, tsk);
- return;
+ return;
}
/* kernel gp */
@@ -670,7 +670,6 @@ clear_dr7:
return regs;
clear_TF_reenable:
- printk("clear_tf_reenable\n");
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
clear_TF:
@@ -681,16 +680,43 @@ clear_TF:
return regs;
}
+static int kernel_math_error(struct pt_regs *regs, char *str)
+{
+ const struct exception_table_entry *fixup;
+ fixup = search_exception_tables(regs->rip);
+ if (fixup) {
+ regs->rip = fixup->fixup;
+ return 1;
+ }
+ notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE);
+#if 0
+ /* This should be a die, but warn only for now */
+ die(str, regs, 0);
+#else
+ printk(KERN_DEBUG "%s: %s at ", current->comm, str);
+ printk_address(regs->rip);
+ printk("\n");
+#endif
+ return 0;
+}
+
/*
* Note that we play around with the 'TS' bit in an attempt to get
* the correct behaviour even in the presence of the asynchronous
* IRQ13 behaviour
*/
-void math_error(void __user *rip)
+asmlinkage void do_coprocessor_error(struct pt_regs *regs)
{
+ void __user *rip = (void __user *)(regs->rip);
struct task_struct * task;
siginfo_t info;
unsigned short cwd, swd;
+
+ conditional_sti(regs);
+ if ((regs->cs & 3) == 0 &&
+ kernel_math_error(regs, "kernel x87 math error"))
+ return;
+
/*
* Save the info for the exception handler and clear the error.
*/
@@ -740,23 +766,23 @@ void math_error(void __user *rip)
force_sig_info(SIGFPE, &info, task);
}
-asmlinkage void do_coprocessor_error(struct pt_regs * regs)
-{
- conditional_sti(regs);
- math_error((void __user *)regs->rip);
-}
-
asmlinkage void bad_intr(void)
{
printk("bad interrupt");
}
-static inline void simd_math_error(void __user *rip)
+asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)
{
+ void __user *rip = (void __user *)(regs->rip);
struct task_struct * task;
siginfo_t info;
unsigned short mxcsr;
+ conditional_sti(regs);
+ if ((regs->cs & 3) == 0 &&
+ kernel_math_error(regs, "simd math error"))
+ return;
+
/*
* Save the info for the exception handler and clear the error.
*/
@@ -799,12 +825,6 @@ static inline void simd_math_error(void __user *rip)
force_sig_info(SIGFPE, &info, task);
}
-asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs)
-{
- conditional_sti(regs);
- simd_math_error((void __user *)regs->rip);
-}
-
asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
{
}
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 21383547ba9bd..e502b7e386acf 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -91,9 +91,6 @@ SECTIONS
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index 1fb138482fb70..9f9515b8e342f 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -108,11 +108,8 @@ EXPORT_SYMBOL(pcibios_penalize_isa_irq);
EXPORT_SYMBOL(pci_mem_start);
#endif
-#ifdef CONFIG_X86_USE_3DNOW
-EXPORT_SYMBOL(_mmx_memcpy);
-EXPORT_SYMBOL(mmx_clear_page);
-EXPORT_SYMBOL(mmx_copy_page);
-#endif
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(cpu_pda);
#ifdef CONFIG_SMP
@@ -182,10 +179,17 @@ EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(__memcpy);
EXPORT_SYMBOL_NOVERS(memcmp);
-/* syscall export needed for misdesigned sound drivers. */
-EXPORT_SYMBOL(sys_read);
-EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_open);
+#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
+/* prototypes are wrong, these are assembly with custom calling functions */
+extern void rwsem_down_read_failed_thunk(void);
+extern void rwsem_wake_thunk(void);
+extern void rwsem_downgrade_thunk(void);
+extern void rwsem_down_write_failed_thunk(void);
+EXPORT_SYMBOL(rwsem_down_read_failed_thunk);
+EXPORT_SYMBOL(rwsem_wake_thunk);
+EXPORT_SYMBOL(rwsem_downgrade_thunk);
+EXPORT_SYMBOL(rwsem_down_write_failed_thunk);
+#endif
EXPORT_SYMBOL(empty_zero_page);
@@ -211,10 +215,9 @@ EXPORT_SYMBOL(init_level4_pgt);
extern unsigned long __supported_pte_mask;
EXPORT_SYMBOL(__supported_pte_mask);
-EXPORT_SYMBOL(clear_page);
-
#ifdef CONFIG_SMP
EXPORT_SYMBOL(flush_tlb_page);
EXPORT_SYMBOL_GPL(flush_tlb_all);
#endif
+EXPORT_SYMBOL(cpu_khz);
diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile
index 32b2064409e3d..6b26a1c1e9fff 100644
--- a/arch/x86_64/lib/Makefile
+++ b/arch/x86_64/lib/Makefile
@@ -8,7 +8,7 @@ obj-y := io.o
lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \
usercopy.o getuser.o putuser.o \
- thunk.o clear_page.o copy_page.o bitstr.o
+ thunk.o clear_page.o copy_page.o bitstr.o bitops.o
lib-y += memcpy.o memmove.o memset.o copy_user.o
lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
diff --git a/arch/x86_64/lib/bitops.c b/arch/x86_64/lib/bitops.c
new file mode 100644
index 0000000000000..6060dd9084aae
--- /dev/null
+++ b/arch/x86_64/lib/bitops.c
@@ -0,0 +1,140 @@
+#include <linux/module.h>
+#include <asm/bitops.h>
+
+#undef find_first_zero_bit
+#undef find_next_zero_bit
+#undef find_first_bit
+#undef find_next_bit
+
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+inline long find_first_zero_bit(const unsigned long * addr, unsigned long size)
+{
+ long d0, d1, d2;
+ long res;
+
+ if (!size)
+ return 0;
+ asm volatile(
+ " repe; scasq\n"
+ " je 1f\n"
+ " xorq -8(%%rdi),%%rax\n"
+ " subq $8,%%rdi\n"
+ " bsfq %%rax,%%rdx\n"
+ "1: subq %[addr],%%rdi\n"
+ " shlq $3,%%rdi\n"
+ " addq %%rdi,%%rdx"
+ :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+ :"0" (0ULL), "1" ((size + 63) >> 6), "2" (addr), "3" (-1ULL),
+ [addr] "r" (addr) : "memory");
+ return res;
+}
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+long find_next_zero_bit (const unsigned long * addr, long size, long offset)
+{
+ unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
+ unsigned long set = 0;
+ unsigned long res, bit = offset&63;
+
+ if (bit) {
+ /*
+ * Look for zero in first word
+ */
+ asm("bsfq %1,%0\n\t"
+ "cmoveq %2,%0"
+ : "=r" (set)
+ : "r" (~(*p >> bit)), "r"(64L));
+ if (set < (64 - bit))
+ return set + offset;
+ set = 64 - bit;
+ p++;
+ }
+ /*
+ * No zero yet, search remaining full words for a zero
+ */
+ res = find_first_zero_bit ((const unsigned long *)p,
+ size - 64 * (p - (unsigned long *) addr));
+ return (offset + set + res);
+}
+
+static inline long
+__find_first_bit(const unsigned long * addr, unsigned long size)
+{
+ long d0, d1;
+ long res;
+
+ asm volatile(
+ " repe; scasq\n"
+ " jz 1f\n"
+ " subq $8,%%rdi\n"
+ " bsfq (%%rdi),%%rax\n"
+ "1: subq %[addr],%%rdi\n"
+ " shlq $3,%%rdi\n"
+ " addq %%rdi,%%rax"
+ :"=a" (res), "=&c" (d0), "=&D" (d1)
+ :"0" (0ULL),
+ "1" ((size + 63) >> 6), "2" (addr),
+ [addr] "r" (addr) : "memory");
+ return res;
+}
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+long find_first_bit(const unsigned long * addr, unsigned long size)
+{
+ return __find_first_bit(addr,size);
+}
+
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+long find_next_bit(const unsigned long * addr, long size, long offset)
+{
+ const unsigned long * p = addr + (offset >> 6);
+ unsigned long set = 0, bit = offset & 63, res;
+
+ if (bit) {
+ /*
+ * Look for nonzero in the first 64 bits:
+ */
+ asm("bsfq %1,%0\n\t"
+ "cmoveq %2,%0\n\t"
+ : "=r" (set)
+ : "r" (*p >> bit), "r" (64L));
+ if (set < (64 - bit))
+ return set + offset;
+ set = 64 - bit;
+ p++;
+ }
+ /*
+ * No set bit yet, search remaining full words for a bit
+ */
+ res = __find_first_bit (p, size - 64 * (p - addr));
+ return (offset + set + res);
+}
+
+EXPORT_SYMBOL(find_next_bit);
+EXPORT_SYMBOL(find_first_bit);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/x86_64/lib/bitstr.c b/arch/x86_64/lib/bitstr.c
index 598d79de83c38..e7ce82a0a332e 100644
--- a/arch/x86_64/lib/bitstr.c
+++ b/arch/x86_64/lib/bitstr.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
#include <asm/bitops.h>
/* Find string of zero bits in a bitmap */
@@ -23,3 +24,5 @@ find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len)
}
return n;
}
+
+EXPORT_SYMBOL(find_next_zero_string);
diff --git a/arch/x86_64/lib/memmove.c b/arch/x86_64/lib/memmove.c
index 12cac5ba7578b..e93d5255fdc96 100644
--- a/arch/x86_64/lib/memmove.c
+++ b/arch/x86_64/lib/memmove.c
@@ -10,18 +10,10 @@ void *memmove(void * dest,const void *src,size_t count)
if (dest < src) {
__inline_memcpy(dest,src,count);
} else {
- /* Could be more clever and move longs */
- unsigned long d0, d1, d2;
- __asm__ __volatile__(
- "std\n\t"
- "rep\n\t"
- "movsb\n\t"
- "cld"
- : "=&c" (d0), "=&S" (d1), "=&D" (d2)
- :"0" (count),
- "1" (count-1+(const char *)src),
- "2" (count-1+(char *)dest)
- :"memory");
+ char *p = (char *) dest + count;
+ char *s = (char *) src + count;
+ while (count--)
+ *--p = *--s;
}
return dest;
}
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 32a1d0ce9df6e..1fa1f48aac405 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -58,16 +58,17 @@ void bust_spinlocks(int yes)
/* Sometimes the CPU reports invalid exceptions on prefetch.
Check that here and ignore.
Opcode checker based on code by Richard Brunner */
-static int is_prefetch(struct pt_regs *regs, unsigned long addr)
+static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr,
+ unsigned long error_code)
{
unsigned char *instr = (unsigned char *)(regs->rip);
int scan_more = 1;
int prefetch = 0;
unsigned char *max_instr = instr + 15;
- /* Avoid recursive faults for this common case */
- if (regs->rip == addr)
- return 0;
+ /* If it was a exec fault ignore */
+ if (error_code & (1<<4))
+ return 0;
/* Code segments in LDT could have a non zero base. Don't check
when that's possible */
@@ -218,6 +219,18 @@ int unhandled_signal(struct task_struct *tsk, int sig)
(tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
}
+static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
+ unsigned long error_code)
+{
+ oops_begin();
+ printk(KERN_ALERT "%s: Corrupted page table at address %lx\n",
+ current->comm, address);
+ dump_pagetable(address);
+ __die("Bad pagetable", regs, error_code);
+ oops_end();
+ do_exit(SIGKILL);
+}
+
int page_fault_trace;
int exception_trace = 1;
@@ -268,11 +281,32 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
mm = tsk->mm;
info.si_code = SEGV_MAPERR;
- /* 5 => page not present and from supervisor mode */
- if (unlikely(!(error_code & 5) &&
- ((address >= VMALLOC_START && address <= VMALLOC_END) ||
- (address >= MODULES_VADDR && address <= MODULES_END))))
- goto vmalloc_fault;
+
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ *
+ * This verifies that the fault happens in kernel space
+ * (error_code & 4) == 0, and that the fault was not a
+ * protection error (error_code & 1) == 0.
+ */
+ if (unlikely(address >= TASK_SIZE)) {
+ if (!(error_code & 5))
+ goto vmalloc_fault;
+ /*
+ * Don't take the mm semaphore here. If we fixup a prefetch
+ * fault we could otherwise deadlock.
+ */
+ goto bad_area_nosemaphore;
+ }
+
+ if (unlikely(error_code & (1 << 3)))
+ goto page_table_corruption;
/*
* If we're in an interrupt or have no user
@@ -351,18 +385,18 @@ bad_area:
bad_area_nosemaphore:
#ifdef CONFIG_IA32_EMULATION
- /* 32bit vsyscall. map on demand. */
- if (test_thread_flag(TIF_IA32) &&
+ /* 32bit vsyscall. map on demand. */
+ if (test_thread_flag(TIF_IA32) &&
address >= 0xffffe000 && address < 0xffffe000 + PAGE_SIZE) {
- if (map_syscall32(mm, address) < 0)
- goto out_of_memory2;
- return;
- }
+ if (map_syscall32(mm, address) < 0)
+ goto out_of_memory2;
+ return;
+ }
#endif
/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
- if (is_prefetch(regs, address))
+ if (is_prefetch(regs, address, error_code))
return;
/* Work around K8 erratum #100 K8 in compat mode
@@ -376,7 +410,7 @@ bad_area_nosemaphore:
return;
if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
- printk(KERN_INFO
+ printk(KERN_INFO
"%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
tsk->comm, tsk->pid, address, regs->rip,
regs->rsp, error_code);
@@ -407,7 +441,7 @@ no_context:
* Hall of shame of CPU/BIOS bugs.
*/
- if (is_prefetch(regs, address))
+ if (is_prefetch(regs, address, error_code))
return;
if (is_errata93(regs, address))
@@ -481,10 +515,8 @@ vmalloc_fault:
* is really there and when yes flush the local TLB.
*/
pgd = pgd_offset_k(address);
- if (pgd != current_pgd_offset_k(address))
- BUG();
if (!pgd_present(*pgd))
- goto bad_area_nosemaphore;
+ goto bad_area_nosemaphore;
pmd = pmd_offset(pgd, address);
if (!pmd_present(*pmd))
goto bad_area_nosemaphore;
@@ -495,4 +527,7 @@ vmalloc_fault:
__flush_tlb_all();
return;
}
+
+page_table_corruption:
+ pgtable_bad(address, regs, error_code);
}
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index f393e3355b99b..fad3c9a9b11eb 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -41,6 +41,10 @@
#define Dprintk(x...)
#endif
+#ifdef CONFIG_GART_IOMMU
+extern int swiotlb;
+#endif
+
extern char _stext[];
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -396,6 +400,8 @@ static inline int page_is_ram (unsigned long pagenr)
return 0;
}
+extern int swiotlb_force;
+
static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
kcore_vsyscall;
@@ -405,7 +411,10 @@ void __init mem_init(void)
int tmp;
#ifdef CONFIG_SWIOTLB
- if (!iommu_aperture && end_pfn >= 0xffffffff>>PAGE_SHIFT)
+ if (swiotlb_force)
+ swiotlb = 1;
+ if (!iommu_aperture &&
+ (end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu))
swiotlb = 1;
if (swiotlb)
swiotlb_init();
@@ -596,7 +605,16 @@ static struct vm_area_struct gate32_vma = {
struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
{
- return test_tsk_thread_flag(tsk, TIF_IA32) ? &gate32_vma : &gate_vma;
+#ifdef CONFIG_IA32_EMULATION
+ if (test_tsk_thread_flag(tsk, TIF_IA32)) {
+ /* lookup code assumes the pages are present. set them up
+ now */
+ if (map_syscall32(tsk->mm, 0xfffe000) < 0)
+ return NULL;
+ return &gate32_vma;
+ }
+#endif
+ return &gate_vma;
}
int in_gate_area(struct task_struct *task, unsigned long addr)
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 598a35c197de8..c38f0cbc02680 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -135,7 +135,7 @@ void __init setup_node_zones(int nodeid)
zones[ZONE_NORMAL] = end_pfn - start_pfn;
}
- free_area_init_node(nodeid, NODE_DATA(nodeid), NULL, zones,
+ free_area_init_node(nodeid, NODE_DATA(nodeid), zones,
start_pfn, NULL);
}
diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
index 291985f0d2e4b..37c92e841deca 100644
--- a/arch/x86_64/pci/Makefile
+++ b/arch/x86_64/pci/Makefile
@@ -3,7 +3,7 @@
#
# Reuse the i386 PCI subsystem
#
-CFLAGS += -I arch/i386/pci
+CFLAGS += -Iarch/i386/pci
obj-y := i386.o
obj-$(CONFIG_PCI_DIRECT)+= direct.o
@@ -13,6 +13,8 @@ obj-y += legacy.o irq.o common.o
# mmconfig has a 64bit special
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
+obj-$(CONFIG_NUMA) += k8-bus.o
+
direct-y += ../../i386/pci/direct.o
acpi-y += ../../i386/pci/acpi.o
legacy-y += ../../i386/pci/legacy.o
diff --git a/arch/x86_64/pci/Makefile-BUS b/arch/x86_64/pci/Makefile-BUS
new file mode 100644
index 0000000000000..291985f0d2e4b
--- /dev/null
+++ b/arch/x86_64/pci/Makefile-BUS
@@ -0,0 +1,22 @@
+#
+# Makefile for X86_64 specific PCI routines
+#
+# Reuse the i386 PCI subsystem
+#
+CFLAGS += -I arch/i386/pci
+
+obj-y := i386.o
+obj-$(CONFIG_PCI_DIRECT)+= direct.o
+obj-y += fixup.o
+obj-$(CONFIG_ACPI_PCI) += acpi.o
+obj-y += legacy.o irq.o common.o
+# mmconfig has a 64bit special
+obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o
+
+direct-y += ../../i386/pci/direct.o
+acpi-y += ../../i386/pci/acpi.o
+legacy-y += ../../i386/pci/legacy.o
+irq-y += ../../i386/pci/irq.o
+common-y += ../../i386/pci/common.o
+fixup-y += ../../i386/pci/fixup.o
+i386-y += ../../i386/pci/i386.o
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
new file mode 100644
index 0000000000000..d1c728acddd76
--- /dev/null
+++ b/arch/x86_64/pci/k8-bus.c
@@ -0,0 +1,74 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/mpspec.h>
+#include <linux/cpumask.h>
+
+/*
+ * This discovers the pcibus <-> node mapping on AMD K8.
+ *
+ * RED-PEN need to call this again on PCI hotplug
+ * RED-PEN empty cpus get reported wrong
+ */
+
+#define NODE_ID_REGISTER 0x60
+#define NODE_ID(dword) (dword & 0x07)
+#define LDT_BUS_NUMBER_REGISTER_0 0x94
+#define LDT_BUS_NUMBER_REGISTER_1 0xB4
+#define LDT_BUS_NUMBER_REGISTER_2 0xD4
+#define NR_LDT_BUS_NUMBER_REGISTERS 3
+#define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
+#define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
+#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
+
+/**
+ * fill_mp_bus_to_cpumask()
+ * fills the mp_bus_to_cpumask array based according to the LDT Bus Number
+ * Registers found in the K8 northbridge
+ */
+__init static int
+fill_mp_bus_to_cpumask(void)
+{
+ struct pci_dev *nb_dev = NULL;
+ int i, j;
+ u32 ldtbus, nid;
+ static int lbnr[3] = {
+ LDT_BUS_NUMBER_REGISTER_0,
+ LDT_BUS_NUMBER_REGISTER_1,
+ LDT_BUS_NUMBER_REGISTER_2
+ };
+
+ while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
+ pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
+
+ for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
+ pci_read_config_dword(nb_dev, lbnr[i], &ldtbus);
+ /*
+ * if there are no busses hanging off of the current
+ * ldt link then both the secondary and subordinate
+ * bus number fields are set to 0.
+ */
+ if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
+ && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
+ for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
+ j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
+ j++)
+ pci_bus_to_cpumask[j] =
+ node_to_cpumask(NODE_ID(nid));
+ }
+ }
+ }
+
+ /* quick sanity check */
+ for (i = 0; i < 256; i++) {
+ if (cpus_empty(pci_bus_to_cpumask[i])) {
+ printk(KERN_ERR
+ "k8-bus.c: bus %i has empty cpu mask\n", i);
+ pci_bus_to_cpumask[i] = CPU_MASK_ALL;
+ }
+ }
+
+ return 0;
+}
+
+fs_initcall(fill_mp_bus_to_cpumask);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index f5bee997bee9e..f048ed35410fc 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -67,6 +67,21 @@ config CRYPTO_SHA512
This code also includes SHA-384, a 384 bit hash with 192 bits
of security against collision attacks.
+config CRYPTO_WHIRLPOOL
+ tristate "Whirlpool digest algorithm"
+ depends on CRYPTO
+ help
+ Whirlpool hash algorithm.
+
+ Whirlpool is part of the NESSIE cryptographic primtives.
+ Whirlpool works on messages shorter than 2^256 bits and
+ produces a 512 bit hash.
+
+ Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard
+
+ See also:
+ http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html
+
config CRYPTO_DES
tristate "DES and Triple DES EDE cipher algorithms"
depends on CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index 04428a65545ad..caebd383e6ae0 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_CRYPTO_MD5) += md5.o
obj-$(CONFIG_CRYPTO_SHA1) += sha1.o
obj-$(CONFIG_CRYPTO_SHA256) += sha256.o
obj-$(CONFIG_CRYPTO_SHA512) += sha512.o
+obj-$(CONFIG_CRYPTO_WHIRLPOOL) += whirlpool.o
obj-$(CONFIG_CRYPTO_DES) += des.o
obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index f1e631b9c885a..91eb1a860f372 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -61,7 +61,8 @@ static char *tvmem;
static char *check[] = {
"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",
- "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", NULL
+ "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
+ "whirlpool", NULL
};
static void
@@ -680,6 +681,7 @@ do_test(void)
test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
+ test_hash("whirlpool", whirlpool_tv_template, WHIRLPOOL_TEST_VECTORS);
test_deflate();
test_crc32c();
#ifdef CONFIG_CRYPTO_HMAC
@@ -791,6 +793,11 @@ do_test(void)
test_cipher ("khazad", MODE_ECB, DECRYPT, khazad_dec_tv_template, KHAZAD_DEC_TEST_VECTORS);
break;
+ case 22:
+ test_hash("whirlpool", whirlpool_tv_template, WHIRLPOOL_TEST_VECTORS);
+ break;
+
+
#ifdef CONFIG_CRYPTO_HMAC
case 100:
test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index 81791c1c01428..536c21f3cfc0c 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -301,6 +301,110 @@ struct hash_testvec sha512_tv_template[] = {
},
};
+
+/*
+ * WHIRLPOOL test vectors from Whirlpool package
+ * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE
+ * submission
+ */
+#define WHIRLPOOL_TEST_VECTORS 8
+
+struct hash_testvec whirlpool_tv_template[] = {
+ {
+ .plaintext = "",
+ .psize = 0,
+ .digest = { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66,
+ 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26,
+ 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8,
+ 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7,
+ 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB,
+ 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57,
+ 0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37,
+ 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 },
+
+
+ }, {
+ .plaintext = "a",
+ .psize = 1,
+ .digest = { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F,
+ 0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7,
+ 0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69,
+ 0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42,
+ 0xD1, 0x1B, 0xC6, 0x45, 0x41, 0x3A, 0xEF, 0xF6,
+ 0x3A, 0x42, 0x39, 0x1A, 0x39, 0x14, 0x5A, 0x59,
+ 0x1A, 0x92, 0x20, 0x0D, 0x56, 0x01, 0x95, 0xE5,
+ 0x3B, 0x47, 0x85, 0x84, 0xFD, 0xAE, 0x23, 0x1A },
+ }, {
+ .plaintext = "abc",
+ .psize = 3,
+ .digest = { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB,
+ 0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B,
+ 0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72,
+ 0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C,
+ 0x71, 0x81, 0xEE, 0xBD, 0xB6, 0xC5, 0x7E, 0x27,
+ 0x7D, 0x0E, 0x34, 0x95, 0x71, 0x14, 0xCB, 0xD6,
+ 0xC7, 0x97, 0xFC, 0x9D, 0x95, 0xD8, 0xB5, 0x82,
+ 0xD2, 0x25, 0x29, 0x20, 0x76, 0xD4, 0xEE, 0xF5 },
+ }, {
+ .plaintext = "message digest",
+ .psize = 14,
+ .digest = { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6,
+ 0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC,
+ 0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C,
+ 0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B,
+ 0x84, 0x21, 0x55, 0x76, 0x59, 0xEF, 0x55, 0xC1,
+ 0x06, 0xB4, 0xB5, 0x2A, 0xC5, 0xA4, 0xAA, 0xA6,
+ 0x92, 0xED, 0x92, 0x00, 0x52, 0x83, 0x8F, 0x33,
+ 0x62, 0xE8, 0x6D, 0xBD, 0x37, 0xA8, 0x90, 0x3E },
+ }, {
+ .plaintext = "abcdefghijklmnopqrstuvwxyz",
+ .psize = 26,
+ .digest = { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9,
+ 0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A,
+ 0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5,
+ 0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B,
+ 0x08, 0xBF, 0x2A, 0x92, 0x51, 0xC3, 0x0B, 0x6A,
+ 0x0B, 0x8A, 0xAE, 0x86, 0x17, 0x7A, 0xB4, 0xA6,
+ 0xF6, 0x8F, 0x67, 0x3E, 0x72, 0x07, 0x86, 0x5D,
+ 0x5D, 0x98, 0x19, 0xA3, 0xDB, 0xA4, 0xEB, 0x3B },
+ }, {
+ .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz0123456789",
+ .psize = 62,
+ .digest = { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B,
+ 0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90,
+ 0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC,
+ 0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E,
+ 0x08, 0xEB, 0xA2, 0x66, 0x29, 0x12, 0x9D, 0x8F,
+ 0xB7, 0xCB, 0x57, 0x21, 0x1B, 0x92, 0x81, 0xA6,
+ 0x55, 0x17, 0xCC, 0x87, 0x9D, 0x7B, 0x96, 0x21,
+ 0x42, 0xC6, 0x5F, 0x5A, 0x7A, 0xF0, 0x14, 0x67 },
+ }, {
+ .plaintext = "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890",
+ .psize = 80,
+ .digest = { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D,
+ 0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0,
+ 0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6,
+ 0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29,
+ 0x4D, 0x5B, 0xD8, 0xDF, 0x2A, 0x6C, 0x44, 0xE5,
+ 0x38, 0xCD, 0x04, 0x7B, 0x26, 0x81, 0xA5, 0x1A,
+ 0x2C, 0x60, 0x48, 0x1E, 0x88, 0xC5, 0xA2, 0x0B,
+ 0x2C, 0x2A, 0x80, 0xCF, 0x3A, 0x9A, 0x08, 0x3B },
+ }, {
+ .plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+ .psize = 32,
+ .digest = { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61,
+ 0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48,
+ 0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62,
+ 0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69,
+ 0x16, 0xBD, 0xC8, 0x03, 0x1B, 0xC5, 0xBE, 0x1B,
+ 0x7B, 0x94, 0x76, 0x39, 0xFE, 0x05, 0x0B, 0x56,
+ 0x93, 0x9B, 0xAA, 0xA0, 0xAD, 0xFF, 0x9A, 0xE6,
+ 0x74, 0x5B, 0x7B, 0x18, 0x1C, 0x3B, 0xE3, 0xFD },
+ },
+};
+
#ifdef CONFIG_CRYPTO_HMAC
/*
* HMAC-MD5 test vectors from RFC2202
diff --git a/crypto/whirlpool.c b/crypto/whirlpool.c
new file mode 100644
index 0000000000000..7f85507fa6c41
--- /dev/null
+++ b/crypto/whirlpool.c
@@ -0,0 +1,1131 @@
+/*
+ * Cryptographic API.
+ *
+ * Whirlpool hashing Algorithm
+ *
+ * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and
+ * Vincent Rijmen. It has been selected as one of cryptographic
+ * primitives by the NESSIE project http://www.cryptonessie.org/
+ *
+ * The original authors have disclaimed all copyright interest in this
+ * code and thus put it in the public domain. The subsequent authors
+ * have put this under the GNU General Public License.
+ *
+ * By Aaron Grothe ajgrothe@yahoo.com, August 23, 2004
+ *
+ * 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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+#define WHIRLPOOL_DIGEST_SIZE 64
+#define WHIRLPOOL_BLOCK_SIZE 64
+#define WHIRLPOOL_LENGTHBYTES 32
+
+#define WHIRLPOOL_ROUNDS 10
+
+struct whirlpool_ctx {
+ u8 bitLength[WHIRLPOOL_LENGTHBYTES];
+ u8 buffer[WHIRLPOOL_BLOCK_SIZE];
+ int bufferBits;
+ int bufferPos;
+ u64 hash[WHIRLPOOL_DIGEST_SIZE/8];
+};
+
+/*
+ * Though Whirlpool is endianness-neutral, the encryption tables are listed
+ * in BIG-ENDIAN format, which is adopted throughout this implementation
+ * (but little-endian notation would be equally suitable if consistently
+ * employed).
+ */
+
+static const u64 C0[256] = {
+ 0x18186018c07830d8ULL, 0x23238c2305af4626ULL, 0xc6c63fc67ef991b8ULL,
+ 0xe8e887e8136fcdfbULL, 0x878726874ca113cbULL, 0xb8b8dab8a9626d11ULL,
+ 0x0101040108050209ULL, 0x4f4f214f426e9e0dULL, 0x3636d836adee6c9bULL,
+ 0xa6a6a2a6590451ffULL, 0xd2d26fd2debdb90cULL, 0xf5f5f3f5fb06f70eULL,
+ 0x7979f979ef80f296ULL, 0x6f6fa16f5fcede30ULL, 0x91917e91fcef3f6dULL,
+ 0x52525552aa07a4f8ULL, 0x60609d6027fdc047ULL, 0xbcbccabc89766535ULL,
+ 0x9b9b569baccd2b37ULL, 0x8e8e028e048c018aULL, 0xa3a3b6a371155bd2ULL,
+ 0x0c0c300c603c186cULL, 0x7b7bf17bff8af684ULL, 0x3535d435b5e16a80ULL,
+ 0x1d1d741de8693af5ULL, 0xe0e0a7e05347ddb3ULL, 0xd7d77bd7f6acb321ULL,
+ 0xc2c22fc25eed999cULL, 0x2e2eb82e6d965c43ULL, 0x4b4b314b627a9629ULL,
+ 0xfefedffea321e15dULL, 0x575741578216aed5ULL, 0x15155415a8412abdULL,
+ 0x7777c1779fb6eee8ULL, 0x3737dc37a5eb6e92ULL, 0xe5e5b3e57b56d79eULL,
+ 0x9f9f469f8cd92313ULL, 0xf0f0e7f0d317fd23ULL, 0x4a4a354a6a7f9420ULL,
+ 0xdada4fda9e95a944ULL, 0x58587d58fa25b0a2ULL, 0xc9c903c906ca8fcfULL,
+ 0x2929a429558d527cULL, 0x0a0a280a5022145aULL, 0xb1b1feb1e14f7f50ULL,
+ 0xa0a0baa0691a5dc9ULL, 0x6b6bb16b7fdad614ULL, 0x85852e855cab17d9ULL,
+ 0xbdbdcebd8173673cULL, 0x5d5d695dd234ba8fULL, 0x1010401080502090ULL,
+ 0xf4f4f7f4f303f507ULL, 0xcbcb0bcb16c08bddULL, 0x3e3ef83eedc67cd3ULL,
+ 0x0505140528110a2dULL, 0x676781671fe6ce78ULL, 0xe4e4b7e47353d597ULL,
+ 0x27279c2725bb4e02ULL, 0x4141194132588273ULL, 0x8b8b168b2c9d0ba7ULL,
+ 0xa7a7a6a7510153f6ULL, 0x7d7de97dcf94fab2ULL, 0x95956e95dcfb3749ULL,
+ 0xd8d847d88e9fad56ULL, 0xfbfbcbfb8b30eb70ULL, 0xeeee9fee2371c1cdULL,
+ 0x7c7ced7cc791f8bbULL, 0x6666856617e3cc71ULL, 0xdddd53dda68ea77bULL,
+ 0x17175c17b84b2eafULL, 0x4747014702468e45ULL, 0x9e9e429e84dc211aULL,
+ 0xcaca0fca1ec589d4ULL, 0x2d2db42d75995a58ULL, 0xbfbfc6bf9179632eULL,
+ 0x07071c07381b0e3fULL, 0xadad8ead012347acULL, 0x5a5a755aea2fb4b0ULL,
+ 0x838336836cb51befULL, 0x3333cc3385ff66b6ULL, 0x636391633ff2c65cULL,
+ 0x02020802100a0412ULL, 0xaaaa92aa39384993ULL, 0x7171d971afa8e2deULL,
+ 0xc8c807c80ecf8dc6ULL, 0x19196419c87d32d1ULL, 0x494939497270923bULL,
+ 0xd9d943d9869aaf5fULL, 0xf2f2eff2c31df931ULL, 0xe3e3abe34b48dba8ULL,
+ 0x5b5b715be22ab6b9ULL, 0x88881a8834920dbcULL, 0x9a9a529aa4c8293eULL,
+ 0x262698262dbe4c0bULL, 0x3232c8328dfa64bfULL, 0xb0b0fab0e94a7d59ULL,
+ 0xe9e983e91b6acff2ULL, 0x0f0f3c0f78331e77ULL, 0xd5d573d5e6a6b733ULL,
+ 0x80803a8074ba1df4ULL, 0xbebec2be997c6127ULL, 0xcdcd13cd26de87ebULL,
+ 0x3434d034bde46889ULL, 0x48483d487a759032ULL, 0xffffdbffab24e354ULL,
+ 0x7a7af57af78ff48dULL, 0x90907a90f4ea3d64ULL, 0x5f5f615fc23ebe9dULL,
+ 0x202080201da0403dULL, 0x6868bd6867d5d00fULL, 0x1a1a681ad07234caULL,
+ 0xaeae82ae192c41b7ULL, 0xb4b4eab4c95e757dULL, 0x54544d549a19a8ceULL,
+ 0x93937693ece53b7fULL, 0x222288220daa442fULL, 0x64648d6407e9c863ULL,
+ 0xf1f1e3f1db12ff2aULL, 0x7373d173bfa2e6ccULL, 0x12124812905a2482ULL,
+ 0x40401d403a5d807aULL, 0x0808200840281048ULL, 0xc3c32bc356e89b95ULL,
+ 0xecec97ec337bc5dfULL, 0xdbdb4bdb9690ab4dULL, 0xa1a1bea1611f5fc0ULL,
+ 0x8d8d0e8d1c830791ULL, 0x3d3df43df5c97ac8ULL, 0x97976697ccf1335bULL,
+ 0x0000000000000000ULL, 0xcfcf1bcf36d483f9ULL, 0x2b2bac2b4587566eULL,
+ 0x7676c57697b3ece1ULL, 0x8282328264b019e6ULL, 0xd6d67fd6fea9b128ULL,
+ 0x1b1b6c1bd87736c3ULL, 0xb5b5eeb5c15b7774ULL, 0xafaf86af112943beULL,
+ 0x6a6ab56a77dfd41dULL, 0x50505d50ba0da0eaULL, 0x45450945124c8a57ULL,
+ 0xf3f3ebf3cb18fb38ULL, 0x3030c0309df060adULL, 0xefef9bef2b74c3c4ULL,
+ 0x3f3ffc3fe5c37edaULL, 0x55554955921caac7ULL, 0xa2a2b2a2791059dbULL,
+ 0xeaea8fea0365c9e9ULL, 0x656589650fecca6aULL, 0xbabad2bab9686903ULL,
+ 0x2f2fbc2f65935e4aULL, 0xc0c027c04ee79d8eULL, 0xdede5fdebe81a160ULL,
+ 0x1c1c701ce06c38fcULL, 0xfdfdd3fdbb2ee746ULL, 0x4d4d294d52649a1fULL,
+ 0x92927292e4e03976ULL, 0x7575c9758fbceafaULL, 0x06061806301e0c36ULL,
+ 0x8a8a128a249809aeULL, 0xb2b2f2b2f940794bULL, 0xe6e6bfe66359d185ULL,
+ 0x0e0e380e70361c7eULL, 0x1f1f7c1ff8633ee7ULL, 0x6262956237f7c455ULL,
+ 0xd4d477d4eea3b53aULL, 0xa8a89aa829324d81ULL, 0x96966296c4f43152ULL,
+ 0xf9f9c3f99b3aef62ULL, 0xc5c533c566f697a3ULL, 0x2525942535b14a10ULL,
+ 0x59597959f220b2abULL, 0x84842a8454ae15d0ULL, 0x7272d572b7a7e4c5ULL,
+ 0x3939e439d5dd72ecULL, 0x4c4c2d4c5a619816ULL, 0x5e5e655eca3bbc94ULL,
+ 0x7878fd78e785f09fULL, 0x3838e038ddd870e5ULL, 0x8c8c0a8c14860598ULL,
+ 0xd1d163d1c6b2bf17ULL, 0xa5a5aea5410b57e4ULL, 0xe2e2afe2434dd9a1ULL,
+ 0x616199612ff8c24eULL, 0xb3b3f6b3f1457b42ULL, 0x2121842115a54234ULL,
+ 0x9c9c4a9c94d62508ULL, 0x1e1e781ef0663ceeULL, 0x4343114322528661ULL,
+ 0xc7c73bc776fc93b1ULL, 0xfcfcd7fcb32be54fULL, 0x0404100420140824ULL,
+ 0x51515951b208a2e3ULL, 0x99995e99bcc72f25ULL, 0x6d6da96d4fc4da22ULL,
+ 0x0d0d340d68391a65ULL, 0xfafacffa8335e979ULL, 0xdfdf5bdfb684a369ULL,
+ 0x7e7ee57ed79bfca9ULL, 0x242490243db44819ULL, 0x3b3bec3bc5d776feULL,
+ 0xabab96ab313d4b9aULL, 0xcece1fce3ed181f0ULL, 0x1111441188552299ULL,
+ 0x8f8f068f0c890383ULL, 0x4e4e254e4a6b9c04ULL, 0xb7b7e6b7d1517366ULL,
+ 0xebeb8beb0b60cbe0ULL, 0x3c3cf03cfdcc78c1ULL, 0x81813e817cbf1ffdULL,
+ 0x94946a94d4fe3540ULL, 0xf7f7fbf7eb0cf31cULL, 0xb9b9deb9a1676f18ULL,
+ 0x13134c13985f268bULL, 0x2c2cb02c7d9c5851ULL, 0xd3d36bd3d6b8bb05ULL,
+ 0xe7e7bbe76b5cd38cULL, 0x6e6ea56e57cbdc39ULL, 0xc4c437c46ef395aaULL,
+ 0x03030c03180f061bULL, 0x565645568a13acdcULL, 0x44440d441a49885eULL,
+ 0x7f7fe17fdf9efea0ULL, 0xa9a99ea921374f88ULL, 0x2a2aa82a4d825467ULL,
+ 0xbbbbd6bbb16d6b0aULL, 0xc1c123c146e29f87ULL, 0x53535153a202a6f1ULL,
+ 0xdcdc57dcae8ba572ULL, 0x0b0b2c0b58271653ULL, 0x9d9d4e9d9cd32701ULL,
+ 0x6c6cad6c47c1d82bULL, 0x3131c43195f562a4ULL, 0x7474cd7487b9e8f3ULL,
+ 0xf6f6fff6e309f115ULL, 0x464605460a438c4cULL, 0xacac8aac092645a5ULL,
+ 0x89891e893c970fb5ULL, 0x14145014a04428b4ULL, 0xe1e1a3e15b42dfbaULL,
+ 0x16165816b04e2ca6ULL, 0x3a3ae83acdd274f7ULL, 0x6969b9696fd0d206ULL,
+ 0x09092409482d1241ULL, 0x7070dd70a7ade0d7ULL, 0xb6b6e2b6d954716fULL,
+ 0xd0d067d0ceb7bd1eULL, 0xeded93ed3b7ec7d6ULL, 0xcccc17cc2edb85e2ULL,
+ 0x424215422a578468ULL, 0x98985a98b4c22d2cULL, 0xa4a4aaa4490e55edULL,
+ 0x2828a0285d885075ULL, 0x5c5c6d5cda31b886ULL, 0xf8f8c7f8933fed6bULL,
+ 0x8686228644a411c2ULL,
+};
+
+static const u64 C1[256] = {
+ 0xd818186018c07830ULL, 0x2623238c2305af46ULL, 0xb8c6c63fc67ef991ULL,
+ 0xfbe8e887e8136fcdULL, 0xcb878726874ca113ULL, 0x11b8b8dab8a9626dULL,
+ 0x0901010401080502ULL, 0x0d4f4f214f426e9eULL, 0x9b3636d836adee6cULL,
+ 0xffa6a6a2a6590451ULL, 0x0cd2d26fd2debdb9ULL, 0x0ef5f5f3f5fb06f7ULL,
+ 0x967979f979ef80f2ULL, 0x306f6fa16f5fcedeULL, 0x6d91917e91fcef3fULL,
+ 0xf852525552aa07a4ULL, 0x4760609d6027fdc0ULL, 0x35bcbccabc897665ULL,
+ 0x379b9b569baccd2bULL, 0x8a8e8e028e048c01ULL, 0xd2a3a3b6a371155bULL,
+ 0x6c0c0c300c603c18ULL, 0x847b7bf17bff8af6ULL, 0x803535d435b5e16aULL,
+ 0xf51d1d741de8693aULL, 0xb3e0e0a7e05347ddULL, 0x21d7d77bd7f6acb3ULL,
+ 0x9cc2c22fc25eed99ULL, 0x432e2eb82e6d965cULL, 0x294b4b314b627a96ULL,
+ 0x5dfefedffea321e1ULL, 0xd5575741578216aeULL, 0xbd15155415a8412aULL,
+ 0xe87777c1779fb6eeULL, 0x923737dc37a5eb6eULL, 0x9ee5e5b3e57b56d7ULL,
+ 0x139f9f469f8cd923ULL, 0x23f0f0e7f0d317fdULL, 0x204a4a354a6a7f94ULL,
+ 0x44dada4fda9e95a9ULL, 0xa258587d58fa25b0ULL, 0xcfc9c903c906ca8fULL,
+ 0x7c2929a429558d52ULL, 0x5a0a0a280a502214ULL, 0x50b1b1feb1e14f7fULL,
+ 0xc9a0a0baa0691a5dULL, 0x146b6bb16b7fdad6ULL, 0xd985852e855cab17ULL,
+ 0x3cbdbdcebd817367ULL, 0x8f5d5d695dd234baULL, 0x9010104010805020ULL,
+ 0x07f4f4f7f4f303f5ULL, 0xddcbcb0bcb16c08bULL, 0xd33e3ef83eedc67cULL,
+ 0x2d0505140528110aULL, 0x78676781671fe6ceULL, 0x97e4e4b7e47353d5ULL,
+ 0x0227279c2725bb4eULL, 0x7341411941325882ULL, 0xa78b8b168b2c9d0bULL,
+ 0xf6a7a7a6a7510153ULL, 0xb27d7de97dcf94faULL, 0x4995956e95dcfb37ULL,
+ 0x56d8d847d88e9fadULL, 0x70fbfbcbfb8b30ebULL, 0xcdeeee9fee2371c1ULL,
+ 0xbb7c7ced7cc791f8ULL, 0x716666856617e3ccULL, 0x7bdddd53dda68ea7ULL,
+ 0xaf17175c17b84b2eULL, 0x454747014702468eULL, 0x1a9e9e429e84dc21ULL,
+ 0xd4caca0fca1ec589ULL, 0x582d2db42d75995aULL, 0x2ebfbfc6bf917963ULL,
+ 0x3f07071c07381b0eULL, 0xacadad8ead012347ULL, 0xb05a5a755aea2fb4ULL,
+ 0xef838336836cb51bULL, 0xb63333cc3385ff66ULL, 0x5c636391633ff2c6ULL,
+ 0x1202020802100a04ULL, 0x93aaaa92aa393849ULL, 0xde7171d971afa8e2ULL,
+ 0xc6c8c807c80ecf8dULL, 0xd119196419c87d32ULL, 0x3b49493949727092ULL,
+ 0x5fd9d943d9869aafULL, 0x31f2f2eff2c31df9ULL, 0xa8e3e3abe34b48dbULL,
+ 0xb95b5b715be22ab6ULL, 0xbc88881a8834920dULL, 0x3e9a9a529aa4c829ULL,
+ 0x0b262698262dbe4cULL, 0xbf3232c8328dfa64ULL, 0x59b0b0fab0e94a7dULL,
+ 0xf2e9e983e91b6acfULL, 0x770f0f3c0f78331eULL, 0x33d5d573d5e6a6b7ULL,
+ 0xf480803a8074ba1dULL, 0x27bebec2be997c61ULL, 0xebcdcd13cd26de87ULL,
+ 0x893434d034bde468ULL, 0x3248483d487a7590ULL, 0x54ffffdbffab24e3ULL,
+ 0x8d7a7af57af78ff4ULL, 0x6490907a90f4ea3dULL, 0x9d5f5f615fc23ebeULL,
+ 0x3d202080201da040ULL, 0x0f6868bd6867d5d0ULL, 0xca1a1a681ad07234ULL,
+ 0xb7aeae82ae192c41ULL, 0x7db4b4eab4c95e75ULL, 0xce54544d549a19a8ULL,
+ 0x7f93937693ece53bULL, 0x2f222288220daa44ULL, 0x6364648d6407e9c8ULL,
+ 0x2af1f1e3f1db12ffULL, 0xcc7373d173bfa2e6ULL, 0x8212124812905a24ULL,
+ 0x7a40401d403a5d80ULL, 0x4808082008402810ULL, 0x95c3c32bc356e89bULL,
+ 0xdfecec97ec337bc5ULL, 0x4ddbdb4bdb9690abULL, 0xc0a1a1bea1611f5fULL,
+ 0x918d8d0e8d1c8307ULL, 0xc83d3df43df5c97aULL, 0x5b97976697ccf133ULL,
+ 0x0000000000000000ULL, 0xf9cfcf1bcf36d483ULL, 0x6e2b2bac2b458756ULL,
+ 0xe17676c57697b3ecULL, 0xe68282328264b019ULL, 0x28d6d67fd6fea9b1ULL,
+ 0xc31b1b6c1bd87736ULL, 0x74b5b5eeb5c15b77ULL, 0xbeafaf86af112943ULL,
+ 0x1d6a6ab56a77dfd4ULL, 0xea50505d50ba0da0ULL, 0x5745450945124c8aULL,
+ 0x38f3f3ebf3cb18fbULL, 0xad3030c0309df060ULL, 0xc4efef9bef2b74c3ULL,
+ 0xda3f3ffc3fe5c37eULL, 0xc755554955921caaULL, 0xdba2a2b2a2791059ULL,
+ 0xe9eaea8fea0365c9ULL, 0x6a656589650feccaULL, 0x03babad2bab96869ULL,
+ 0x4a2f2fbc2f65935eULL, 0x8ec0c027c04ee79dULL, 0x60dede5fdebe81a1ULL,
+ 0xfc1c1c701ce06c38ULL, 0x46fdfdd3fdbb2ee7ULL, 0x1f4d4d294d52649aULL,
+ 0x7692927292e4e039ULL, 0xfa7575c9758fbceaULL, 0x3606061806301e0cULL,
+ 0xae8a8a128a249809ULL, 0x4bb2b2f2b2f94079ULL, 0x85e6e6bfe66359d1ULL,
+ 0x7e0e0e380e70361cULL, 0xe71f1f7c1ff8633eULL, 0x556262956237f7c4ULL,
+ 0x3ad4d477d4eea3b5ULL, 0x81a8a89aa829324dULL, 0x5296966296c4f431ULL,
+ 0x62f9f9c3f99b3aefULL, 0xa3c5c533c566f697ULL, 0x102525942535b14aULL,
+ 0xab59597959f220b2ULL, 0xd084842a8454ae15ULL, 0xc57272d572b7a7e4ULL,
+ 0xec3939e439d5dd72ULL, 0x164c4c2d4c5a6198ULL, 0x945e5e655eca3bbcULL,
+ 0x9f7878fd78e785f0ULL, 0xe53838e038ddd870ULL, 0x988c8c0a8c148605ULL,
+ 0x17d1d163d1c6b2bfULL, 0xe4a5a5aea5410b57ULL, 0xa1e2e2afe2434dd9ULL,
+ 0x4e616199612ff8c2ULL, 0x42b3b3f6b3f1457bULL, 0x342121842115a542ULL,
+ 0x089c9c4a9c94d625ULL, 0xee1e1e781ef0663cULL, 0x6143431143225286ULL,
+ 0xb1c7c73bc776fc93ULL, 0x4ffcfcd7fcb32be5ULL, 0x2404041004201408ULL,
+ 0xe351515951b208a2ULL, 0x2599995e99bcc72fULL, 0x226d6da96d4fc4daULL,
+ 0x650d0d340d68391aULL, 0x79fafacffa8335e9ULL, 0x69dfdf5bdfb684a3ULL,
+ 0xa97e7ee57ed79bfcULL, 0x19242490243db448ULL, 0xfe3b3bec3bc5d776ULL,
+ 0x9aabab96ab313d4bULL, 0xf0cece1fce3ed181ULL, 0x9911114411885522ULL,
+ 0x838f8f068f0c8903ULL, 0x044e4e254e4a6b9cULL, 0x66b7b7e6b7d15173ULL,
+ 0xe0ebeb8beb0b60cbULL, 0xc13c3cf03cfdcc78ULL, 0xfd81813e817cbf1fULL,
+ 0x4094946a94d4fe35ULL, 0x1cf7f7fbf7eb0cf3ULL, 0x18b9b9deb9a1676fULL,
+ 0x8b13134c13985f26ULL, 0x512c2cb02c7d9c58ULL, 0x05d3d36bd3d6b8bbULL,
+ 0x8ce7e7bbe76b5cd3ULL, 0x396e6ea56e57cbdcULL, 0xaac4c437c46ef395ULL,
+ 0x1b03030c03180f06ULL, 0xdc565645568a13acULL, 0x5e44440d441a4988ULL,
+ 0xa07f7fe17fdf9efeULL, 0x88a9a99ea921374fULL, 0x672a2aa82a4d8254ULL,
+ 0x0abbbbd6bbb16d6bULL, 0x87c1c123c146e29fULL, 0xf153535153a202a6ULL,
+ 0x72dcdc57dcae8ba5ULL, 0x530b0b2c0b582716ULL, 0x019d9d4e9d9cd327ULL,
+ 0x2b6c6cad6c47c1d8ULL, 0xa43131c43195f562ULL, 0xf37474cd7487b9e8ULL,
+ 0x15f6f6fff6e309f1ULL, 0x4c464605460a438cULL, 0xa5acac8aac092645ULL,
+ 0xb589891e893c970fULL, 0xb414145014a04428ULL, 0xbae1e1a3e15b42dfULL,
+ 0xa616165816b04e2cULL, 0xf73a3ae83acdd274ULL, 0x066969b9696fd0d2ULL,
+ 0x4109092409482d12ULL, 0xd77070dd70a7ade0ULL, 0x6fb6b6e2b6d95471ULL,
+ 0x1ed0d067d0ceb7bdULL, 0xd6eded93ed3b7ec7ULL, 0xe2cccc17cc2edb85ULL,
+ 0x68424215422a5784ULL, 0x2c98985a98b4c22dULL, 0xeda4a4aaa4490e55ULL,
+ 0x752828a0285d8850ULL, 0x865c5c6d5cda31b8ULL, 0x6bf8f8c7f8933fedULL,
+ 0xc28686228644a411ULL,
+};
+
+static const u64 C2[256] = {
+ 0x30d818186018c078ULL, 0x462623238c2305afULL, 0x91b8c6c63fc67ef9ULL,
+ 0xcdfbe8e887e8136fULL, 0x13cb878726874ca1ULL, 0x6d11b8b8dab8a962ULL,
+ 0x0209010104010805ULL, 0x9e0d4f4f214f426eULL, 0x6c9b3636d836adeeULL,
+ 0x51ffa6a6a2a65904ULL, 0xb90cd2d26fd2debdULL, 0xf70ef5f5f3f5fb06ULL,
+ 0xf2967979f979ef80ULL, 0xde306f6fa16f5fceULL, 0x3f6d91917e91fcefULL,
+ 0xa4f852525552aa07ULL, 0xc04760609d6027fdULL, 0x6535bcbccabc8976ULL,
+ 0x2b379b9b569baccdULL, 0x018a8e8e028e048cULL, 0x5bd2a3a3b6a37115ULL,
+ 0x186c0c0c300c603cULL, 0xf6847b7bf17bff8aULL, 0x6a803535d435b5e1ULL,
+ 0x3af51d1d741de869ULL, 0xddb3e0e0a7e05347ULL, 0xb321d7d77bd7f6acULL,
+ 0x999cc2c22fc25eedULL, 0x5c432e2eb82e6d96ULL, 0x96294b4b314b627aULL,
+ 0xe15dfefedffea321ULL, 0xaed5575741578216ULL, 0x2abd15155415a841ULL,
+ 0xeee87777c1779fb6ULL, 0x6e923737dc37a5ebULL, 0xd79ee5e5b3e57b56ULL,
+ 0x23139f9f469f8cd9ULL, 0xfd23f0f0e7f0d317ULL, 0x94204a4a354a6a7fULL,
+ 0xa944dada4fda9e95ULL, 0xb0a258587d58fa25ULL, 0x8fcfc9c903c906caULL,
+ 0x527c2929a429558dULL, 0x145a0a0a280a5022ULL, 0x7f50b1b1feb1e14fULL,
+ 0x5dc9a0a0baa0691aULL, 0xd6146b6bb16b7fdaULL, 0x17d985852e855cabULL,
+ 0x673cbdbdcebd8173ULL, 0xba8f5d5d695dd234ULL, 0x2090101040108050ULL,
+ 0xf507f4f4f7f4f303ULL, 0x8bddcbcb0bcb16c0ULL, 0x7cd33e3ef83eedc6ULL,
+ 0x0a2d050514052811ULL, 0xce78676781671fe6ULL, 0xd597e4e4b7e47353ULL,
+ 0x4e0227279c2725bbULL, 0x8273414119413258ULL, 0x0ba78b8b168b2c9dULL,
+ 0x53f6a7a7a6a75101ULL, 0xfab27d7de97dcf94ULL, 0x374995956e95dcfbULL,
+ 0xad56d8d847d88e9fULL, 0xeb70fbfbcbfb8b30ULL, 0xc1cdeeee9fee2371ULL,
+ 0xf8bb7c7ced7cc791ULL, 0xcc716666856617e3ULL, 0xa77bdddd53dda68eULL,
+ 0x2eaf17175c17b84bULL, 0x8e45474701470246ULL, 0x211a9e9e429e84dcULL,
+ 0x89d4caca0fca1ec5ULL, 0x5a582d2db42d7599ULL, 0x632ebfbfc6bf9179ULL,
+ 0x0e3f07071c07381bULL, 0x47acadad8ead0123ULL, 0xb4b05a5a755aea2fULL,
+ 0x1bef838336836cb5ULL, 0x66b63333cc3385ffULL, 0xc65c636391633ff2ULL,
+ 0x041202020802100aULL, 0x4993aaaa92aa3938ULL, 0xe2de7171d971afa8ULL,
+ 0x8dc6c8c807c80ecfULL, 0x32d119196419c87dULL, 0x923b494939497270ULL,
+ 0xaf5fd9d943d9869aULL, 0xf931f2f2eff2c31dULL, 0xdba8e3e3abe34b48ULL,
+ 0xb6b95b5b715be22aULL, 0x0dbc88881a883492ULL, 0x293e9a9a529aa4c8ULL,
+ 0x4c0b262698262dbeULL, 0x64bf3232c8328dfaULL, 0x7d59b0b0fab0e94aULL,
+ 0xcff2e9e983e91b6aULL, 0x1e770f0f3c0f7833ULL, 0xb733d5d573d5e6a6ULL,
+ 0x1df480803a8074baULL, 0x6127bebec2be997cULL, 0x87ebcdcd13cd26deULL,
+ 0x68893434d034bde4ULL, 0x903248483d487a75ULL, 0xe354ffffdbffab24ULL,
+ 0xf48d7a7af57af78fULL, 0x3d6490907a90f4eaULL, 0xbe9d5f5f615fc23eULL,
+ 0x403d202080201da0ULL, 0xd00f6868bd6867d5ULL, 0x34ca1a1a681ad072ULL,
+ 0x41b7aeae82ae192cULL, 0x757db4b4eab4c95eULL, 0xa8ce54544d549a19ULL,
+ 0x3b7f93937693ece5ULL, 0x442f222288220daaULL, 0xc86364648d6407e9ULL,
+ 0xff2af1f1e3f1db12ULL, 0xe6cc7373d173bfa2ULL, 0x248212124812905aULL,
+ 0x807a40401d403a5dULL, 0x1048080820084028ULL, 0x9b95c3c32bc356e8ULL,
+ 0xc5dfecec97ec337bULL, 0xab4ddbdb4bdb9690ULL, 0x5fc0a1a1bea1611fULL,
+ 0x07918d8d0e8d1c83ULL, 0x7ac83d3df43df5c9ULL, 0x335b97976697ccf1ULL,
+ 0x0000000000000000ULL, 0x83f9cfcf1bcf36d4ULL, 0x566e2b2bac2b4587ULL,
+ 0xece17676c57697b3ULL, 0x19e68282328264b0ULL, 0xb128d6d67fd6fea9ULL,
+ 0x36c31b1b6c1bd877ULL, 0x7774b5b5eeb5c15bULL, 0x43beafaf86af1129ULL,
+ 0xd41d6a6ab56a77dfULL, 0xa0ea50505d50ba0dULL, 0x8a5745450945124cULL,
+ 0xfb38f3f3ebf3cb18ULL, 0x60ad3030c0309df0ULL, 0xc3c4efef9bef2b74ULL,
+ 0x7eda3f3ffc3fe5c3ULL, 0xaac755554955921cULL, 0x59dba2a2b2a27910ULL,
+ 0xc9e9eaea8fea0365ULL, 0xca6a656589650fecULL, 0x6903babad2bab968ULL,
+ 0x5e4a2f2fbc2f6593ULL, 0x9d8ec0c027c04ee7ULL, 0xa160dede5fdebe81ULL,
+ 0x38fc1c1c701ce06cULL, 0xe746fdfdd3fdbb2eULL, 0x9a1f4d4d294d5264ULL,
+ 0x397692927292e4e0ULL, 0xeafa7575c9758fbcULL, 0x0c3606061806301eULL,
+ 0x09ae8a8a128a2498ULL, 0x794bb2b2f2b2f940ULL, 0xd185e6e6bfe66359ULL,
+ 0x1c7e0e0e380e7036ULL, 0x3ee71f1f7c1ff863ULL, 0xc4556262956237f7ULL,
+ 0xb53ad4d477d4eea3ULL, 0x4d81a8a89aa82932ULL, 0x315296966296c4f4ULL,
+ 0xef62f9f9c3f99b3aULL, 0x97a3c5c533c566f6ULL, 0x4a102525942535b1ULL,
+ 0xb2ab59597959f220ULL, 0x15d084842a8454aeULL, 0xe4c57272d572b7a7ULL,
+ 0x72ec3939e439d5ddULL, 0x98164c4c2d4c5a61ULL, 0xbc945e5e655eca3bULL,
+ 0xf09f7878fd78e785ULL, 0x70e53838e038ddd8ULL, 0x05988c8c0a8c1486ULL,
+ 0xbf17d1d163d1c6b2ULL, 0x57e4a5a5aea5410bULL, 0xd9a1e2e2afe2434dULL,
+ 0xc24e616199612ff8ULL, 0x7b42b3b3f6b3f145ULL, 0x42342121842115a5ULL,
+ 0x25089c9c4a9c94d6ULL, 0x3cee1e1e781ef066ULL, 0x8661434311432252ULL,
+ 0x93b1c7c73bc776fcULL, 0xe54ffcfcd7fcb32bULL, 0x0824040410042014ULL,
+ 0xa2e351515951b208ULL, 0x2f2599995e99bcc7ULL, 0xda226d6da96d4fc4ULL,
+ 0x1a650d0d340d6839ULL, 0xe979fafacffa8335ULL, 0xa369dfdf5bdfb684ULL,
+ 0xfca97e7ee57ed79bULL, 0x4819242490243db4ULL, 0x76fe3b3bec3bc5d7ULL,
+ 0x4b9aabab96ab313dULL, 0x81f0cece1fce3ed1ULL, 0x2299111144118855ULL,
+ 0x03838f8f068f0c89ULL, 0x9c044e4e254e4a6bULL, 0x7366b7b7e6b7d151ULL,
+ 0xcbe0ebeb8beb0b60ULL, 0x78c13c3cf03cfdccULL, 0x1ffd81813e817cbfULL,
+ 0x354094946a94d4feULL, 0xf31cf7f7fbf7eb0cULL, 0x6f18b9b9deb9a167ULL,
+ 0x268b13134c13985fULL, 0x58512c2cb02c7d9cULL, 0xbb05d3d36bd3d6b8ULL,
+ 0xd38ce7e7bbe76b5cULL, 0xdc396e6ea56e57cbULL, 0x95aac4c437c46ef3ULL,
+ 0x061b03030c03180fULL, 0xacdc565645568a13ULL, 0x885e44440d441a49ULL,
+ 0xfea07f7fe17fdf9eULL, 0x4f88a9a99ea92137ULL, 0x54672a2aa82a4d82ULL,
+ 0x6b0abbbbd6bbb16dULL, 0x9f87c1c123c146e2ULL, 0xa6f153535153a202ULL,
+ 0xa572dcdc57dcae8bULL, 0x16530b0b2c0b5827ULL, 0x27019d9d4e9d9cd3ULL,
+ 0xd82b6c6cad6c47c1ULL, 0x62a43131c43195f5ULL, 0xe8f37474cd7487b9ULL,
+ 0xf115f6f6fff6e309ULL, 0x8c4c464605460a43ULL, 0x45a5acac8aac0926ULL,
+ 0x0fb589891e893c97ULL, 0x28b414145014a044ULL, 0xdfbae1e1a3e15b42ULL,
+ 0x2ca616165816b04eULL, 0x74f73a3ae83acdd2ULL, 0xd2066969b9696fd0ULL,
+ 0x124109092409482dULL, 0xe0d77070dd70a7adULL, 0x716fb6b6e2b6d954ULL,
+ 0xbd1ed0d067d0ceb7ULL, 0xc7d6eded93ed3b7eULL, 0x85e2cccc17cc2edbULL,
+ 0x8468424215422a57ULL, 0x2d2c98985a98b4c2ULL, 0x55eda4a4aaa4490eULL,
+ 0x50752828a0285d88ULL, 0xb8865c5c6d5cda31ULL, 0xed6bf8f8c7f8933fULL,
+ 0x11c28686228644a4ULL,
+};
+
+static const u64 C3[256] = {
+ 0x7830d818186018c0ULL, 0xaf462623238c2305ULL, 0xf991b8c6c63fc67eULL,
+ 0x6fcdfbe8e887e813ULL, 0xa113cb878726874cULL, 0x626d11b8b8dab8a9ULL,
+ 0x0502090101040108ULL, 0x6e9e0d4f4f214f42ULL, 0xee6c9b3636d836adULL,
+ 0x0451ffa6a6a2a659ULL, 0xbdb90cd2d26fd2deULL, 0x06f70ef5f5f3f5fbULL,
+ 0x80f2967979f979efULL, 0xcede306f6fa16f5fULL, 0xef3f6d91917e91fcULL,
+ 0x07a4f852525552aaULL, 0xfdc04760609d6027ULL, 0x766535bcbccabc89ULL,
+ 0xcd2b379b9b569bacULL, 0x8c018a8e8e028e04ULL, 0x155bd2a3a3b6a371ULL,
+ 0x3c186c0c0c300c60ULL, 0x8af6847b7bf17bffULL, 0xe16a803535d435b5ULL,
+ 0x693af51d1d741de8ULL, 0x47ddb3e0e0a7e053ULL, 0xacb321d7d77bd7f6ULL,
+ 0xed999cc2c22fc25eULL, 0x965c432e2eb82e6dULL, 0x7a96294b4b314b62ULL,
+ 0x21e15dfefedffea3ULL, 0x16aed55757415782ULL, 0x412abd15155415a8ULL,
+ 0xb6eee87777c1779fULL, 0xeb6e923737dc37a5ULL, 0x56d79ee5e5b3e57bULL,
+ 0xd923139f9f469f8cULL, 0x17fd23f0f0e7f0d3ULL, 0x7f94204a4a354a6aULL,
+ 0x95a944dada4fda9eULL, 0x25b0a258587d58faULL, 0xca8fcfc9c903c906ULL,
+ 0x8d527c2929a42955ULL, 0x22145a0a0a280a50ULL, 0x4f7f50b1b1feb1e1ULL,
+ 0x1a5dc9a0a0baa069ULL, 0xdad6146b6bb16b7fULL, 0xab17d985852e855cULL,
+ 0x73673cbdbdcebd81ULL, 0x34ba8f5d5d695dd2ULL, 0x5020901010401080ULL,
+ 0x03f507f4f4f7f4f3ULL, 0xc08bddcbcb0bcb16ULL, 0xc67cd33e3ef83eedULL,
+ 0x110a2d0505140528ULL, 0xe6ce78676781671fULL, 0x53d597e4e4b7e473ULL,
+ 0xbb4e0227279c2725ULL, 0x5882734141194132ULL, 0x9d0ba78b8b168b2cULL,
+ 0x0153f6a7a7a6a751ULL, 0x94fab27d7de97dcfULL, 0xfb374995956e95dcULL,
+ 0x9fad56d8d847d88eULL, 0x30eb70fbfbcbfb8bULL, 0x71c1cdeeee9fee23ULL,
+ 0x91f8bb7c7ced7cc7ULL, 0xe3cc716666856617ULL, 0x8ea77bdddd53dda6ULL,
+ 0x4b2eaf17175c17b8ULL, 0x468e454747014702ULL, 0xdc211a9e9e429e84ULL,
+ 0xc589d4caca0fca1eULL, 0x995a582d2db42d75ULL, 0x79632ebfbfc6bf91ULL,
+ 0x1b0e3f07071c0738ULL, 0x2347acadad8ead01ULL, 0x2fb4b05a5a755aeaULL,
+ 0xb51bef838336836cULL, 0xff66b63333cc3385ULL, 0xf2c65c636391633fULL,
+ 0x0a04120202080210ULL, 0x384993aaaa92aa39ULL, 0xa8e2de7171d971afULL,
+ 0xcf8dc6c8c807c80eULL, 0x7d32d119196419c8ULL, 0x70923b4949394972ULL,
+ 0x9aaf5fd9d943d986ULL, 0x1df931f2f2eff2c3ULL, 0x48dba8e3e3abe34bULL,
+ 0x2ab6b95b5b715be2ULL, 0x920dbc88881a8834ULL, 0xc8293e9a9a529aa4ULL,
+ 0xbe4c0b262698262dULL, 0xfa64bf3232c8328dULL, 0x4a7d59b0b0fab0e9ULL,
+ 0x6acff2e9e983e91bULL, 0x331e770f0f3c0f78ULL, 0xa6b733d5d573d5e6ULL,
+ 0xba1df480803a8074ULL, 0x7c6127bebec2be99ULL, 0xde87ebcdcd13cd26ULL,
+ 0xe468893434d034bdULL, 0x75903248483d487aULL, 0x24e354ffffdbffabULL,
+ 0x8ff48d7a7af57af7ULL, 0xea3d6490907a90f4ULL, 0x3ebe9d5f5f615fc2ULL,
+ 0xa0403d202080201dULL, 0xd5d00f6868bd6867ULL, 0x7234ca1a1a681ad0ULL,
+ 0x2c41b7aeae82ae19ULL, 0x5e757db4b4eab4c9ULL, 0x19a8ce54544d549aULL,
+ 0xe53b7f93937693ecULL, 0xaa442f222288220dULL, 0xe9c86364648d6407ULL,
+ 0x12ff2af1f1e3f1dbULL, 0xa2e6cc7373d173bfULL, 0x5a24821212481290ULL,
+ 0x5d807a40401d403aULL, 0x2810480808200840ULL, 0xe89b95c3c32bc356ULL,
+ 0x7bc5dfecec97ec33ULL, 0x90ab4ddbdb4bdb96ULL, 0x1f5fc0a1a1bea161ULL,
+ 0x8307918d8d0e8d1cULL, 0xc97ac83d3df43df5ULL, 0xf1335b97976697ccULL,
+ 0x0000000000000000ULL, 0xd483f9cfcf1bcf36ULL, 0x87566e2b2bac2b45ULL,
+ 0xb3ece17676c57697ULL, 0xb019e68282328264ULL, 0xa9b128d6d67fd6feULL,
+ 0x7736c31b1b6c1bd8ULL, 0x5b7774b5b5eeb5c1ULL, 0x2943beafaf86af11ULL,
+ 0xdfd41d6a6ab56a77ULL, 0x0da0ea50505d50baULL, 0x4c8a574545094512ULL,
+ 0x18fb38f3f3ebf3cbULL, 0xf060ad3030c0309dULL, 0x74c3c4efef9bef2bULL,
+ 0xc37eda3f3ffc3fe5ULL, 0x1caac75555495592ULL, 0x1059dba2a2b2a279ULL,
+ 0x65c9e9eaea8fea03ULL, 0xecca6a656589650fULL, 0x686903babad2bab9ULL,
+ 0x935e4a2f2fbc2f65ULL, 0xe79d8ec0c027c04eULL, 0x81a160dede5fdebeULL,
+ 0x6c38fc1c1c701ce0ULL, 0x2ee746fdfdd3fdbbULL, 0x649a1f4d4d294d52ULL,
+ 0xe0397692927292e4ULL, 0xbceafa7575c9758fULL, 0x1e0c360606180630ULL,
+ 0x9809ae8a8a128a24ULL, 0x40794bb2b2f2b2f9ULL, 0x59d185e6e6bfe663ULL,
+ 0x361c7e0e0e380e70ULL, 0x633ee71f1f7c1ff8ULL, 0xf7c4556262956237ULL,
+ 0xa3b53ad4d477d4eeULL, 0x324d81a8a89aa829ULL, 0xf4315296966296c4ULL,
+ 0x3aef62f9f9c3f99bULL, 0xf697a3c5c533c566ULL, 0xb14a102525942535ULL,
+ 0x20b2ab59597959f2ULL, 0xae15d084842a8454ULL, 0xa7e4c57272d572b7ULL,
+ 0xdd72ec3939e439d5ULL, 0x6198164c4c2d4c5aULL, 0x3bbc945e5e655ecaULL,
+ 0x85f09f7878fd78e7ULL, 0xd870e53838e038ddULL, 0x8605988c8c0a8c14ULL,
+ 0xb2bf17d1d163d1c6ULL, 0x0b57e4a5a5aea541ULL, 0x4dd9a1e2e2afe243ULL,
+ 0xf8c24e616199612fULL, 0x457b42b3b3f6b3f1ULL, 0xa542342121842115ULL,
+ 0xd625089c9c4a9c94ULL, 0x663cee1e1e781ef0ULL, 0x5286614343114322ULL,
+ 0xfc93b1c7c73bc776ULL, 0x2be54ffcfcd7fcb3ULL, 0x1408240404100420ULL,
+ 0x08a2e351515951b2ULL, 0xc72f2599995e99bcULL, 0xc4da226d6da96d4fULL,
+ 0x391a650d0d340d68ULL, 0x35e979fafacffa83ULL, 0x84a369dfdf5bdfb6ULL,
+ 0x9bfca97e7ee57ed7ULL, 0xb44819242490243dULL, 0xd776fe3b3bec3bc5ULL,
+ 0x3d4b9aabab96ab31ULL, 0xd181f0cece1fce3eULL, 0x5522991111441188ULL,
+ 0x8903838f8f068f0cULL, 0x6b9c044e4e254e4aULL, 0x517366b7b7e6b7d1ULL,
+ 0x60cbe0ebeb8beb0bULL, 0xcc78c13c3cf03cfdULL, 0xbf1ffd81813e817cULL,
+ 0xfe354094946a94d4ULL, 0x0cf31cf7f7fbf7ebULL, 0x676f18b9b9deb9a1ULL,
+ 0x5f268b13134c1398ULL, 0x9c58512c2cb02c7dULL, 0xb8bb05d3d36bd3d6ULL,
+ 0x5cd38ce7e7bbe76bULL, 0xcbdc396e6ea56e57ULL, 0xf395aac4c437c46eULL,
+ 0x0f061b03030c0318ULL, 0x13acdc565645568aULL, 0x49885e44440d441aULL,
+ 0x9efea07f7fe17fdfULL, 0x374f88a9a99ea921ULL, 0x8254672a2aa82a4dULL,
+ 0x6d6b0abbbbd6bbb1ULL, 0xe29f87c1c123c146ULL, 0x02a6f153535153a2ULL,
+ 0x8ba572dcdc57dcaeULL, 0x2716530b0b2c0b58ULL, 0xd327019d9d4e9d9cULL,
+ 0xc1d82b6c6cad6c47ULL, 0xf562a43131c43195ULL, 0xb9e8f37474cd7487ULL,
+ 0x09f115f6f6fff6e3ULL, 0x438c4c464605460aULL, 0x2645a5acac8aac09ULL,
+ 0x970fb589891e893cULL, 0x4428b414145014a0ULL, 0x42dfbae1e1a3e15bULL,
+ 0x4e2ca616165816b0ULL, 0xd274f73a3ae83acdULL, 0xd0d2066969b9696fULL,
+ 0x2d12410909240948ULL, 0xade0d77070dd70a7ULL, 0x54716fb6b6e2b6d9ULL,
+ 0xb7bd1ed0d067d0ceULL, 0x7ec7d6eded93ed3bULL, 0xdb85e2cccc17cc2eULL,
+ 0x578468424215422aULL, 0xc22d2c98985a98b4ULL, 0x0e55eda4a4aaa449ULL,
+ 0x8850752828a0285dULL, 0x31b8865c5c6d5cdaULL, 0x3fed6bf8f8c7f893ULL,
+ 0xa411c28686228644ULL,
+};
+
+static const u64 C4[256] = {
+ 0xc07830d818186018ULL, 0x05af462623238c23ULL, 0x7ef991b8c6c63fc6ULL,
+ 0x136fcdfbe8e887e8ULL, 0x4ca113cb87872687ULL, 0xa9626d11b8b8dab8ULL,
+ 0x0805020901010401ULL, 0x426e9e0d4f4f214fULL, 0xadee6c9b3636d836ULL,
+ 0x590451ffa6a6a2a6ULL, 0xdebdb90cd2d26fd2ULL, 0xfb06f70ef5f5f3f5ULL,
+ 0xef80f2967979f979ULL, 0x5fcede306f6fa16fULL, 0xfcef3f6d91917e91ULL,
+ 0xaa07a4f852525552ULL, 0x27fdc04760609d60ULL, 0x89766535bcbccabcULL,
+ 0xaccd2b379b9b569bULL, 0x048c018a8e8e028eULL, 0x71155bd2a3a3b6a3ULL,
+ 0x603c186c0c0c300cULL, 0xff8af6847b7bf17bULL, 0xb5e16a803535d435ULL,
+ 0xe8693af51d1d741dULL, 0x5347ddb3e0e0a7e0ULL, 0xf6acb321d7d77bd7ULL,
+ 0x5eed999cc2c22fc2ULL, 0x6d965c432e2eb82eULL, 0x627a96294b4b314bULL,
+ 0xa321e15dfefedffeULL, 0x8216aed557574157ULL, 0xa8412abd15155415ULL,
+ 0x9fb6eee87777c177ULL, 0xa5eb6e923737dc37ULL, 0x7b56d79ee5e5b3e5ULL,
+ 0x8cd923139f9f469fULL, 0xd317fd23f0f0e7f0ULL, 0x6a7f94204a4a354aULL,
+ 0x9e95a944dada4fdaULL, 0xfa25b0a258587d58ULL, 0x06ca8fcfc9c903c9ULL,
+ 0x558d527c2929a429ULL, 0x5022145a0a0a280aULL, 0xe14f7f50b1b1feb1ULL,
+ 0x691a5dc9a0a0baa0ULL, 0x7fdad6146b6bb16bULL, 0x5cab17d985852e85ULL,
+ 0x8173673cbdbdcebdULL, 0xd234ba8f5d5d695dULL, 0x8050209010104010ULL,
+ 0xf303f507f4f4f7f4ULL, 0x16c08bddcbcb0bcbULL, 0xedc67cd33e3ef83eULL,
+ 0x28110a2d05051405ULL, 0x1fe6ce7867678167ULL, 0x7353d597e4e4b7e4ULL,
+ 0x25bb4e0227279c27ULL, 0x3258827341411941ULL, 0x2c9d0ba78b8b168bULL,
+ 0x510153f6a7a7a6a7ULL, 0xcf94fab27d7de97dULL, 0xdcfb374995956e95ULL,
+ 0x8e9fad56d8d847d8ULL, 0x8b30eb70fbfbcbfbULL, 0x2371c1cdeeee9feeULL,
+ 0xc791f8bb7c7ced7cULL, 0x17e3cc7166668566ULL, 0xa68ea77bdddd53ddULL,
+ 0xb84b2eaf17175c17ULL, 0x02468e4547470147ULL, 0x84dc211a9e9e429eULL,
+ 0x1ec589d4caca0fcaULL, 0x75995a582d2db42dULL, 0x9179632ebfbfc6bfULL,
+ 0x381b0e3f07071c07ULL, 0x012347acadad8eadULL, 0xea2fb4b05a5a755aULL,
+ 0x6cb51bef83833683ULL, 0x85ff66b63333cc33ULL, 0x3ff2c65c63639163ULL,
+ 0x100a041202020802ULL, 0x39384993aaaa92aaULL, 0xafa8e2de7171d971ULL,
+ 0x0ecf8dc6c8c807c8ULL, 0xc87d32d119196419ULL, 0x7270923b49493949ULL,
+ 0x869aaf5fd9d943d9ULL, 0xc31df931f2f2eff2ULL, 0x4b48dba8e3e3abe3ULL,
+ 0xe22ab6b95b5b715bULL, 0x34920dbc88881a88ULL, 0xa4c8293e9a9a529aULL,
+ 0x2dbe4c0b26269826ULL, 0x8dfa64bf3232c832ULL, 0xe94a7d59b0b0fab0ULL,
+ 0x1b6acff2e9e983e9ULL, 0x78331e770f0f3c0fULL, 0xe6a6b733d5d573d5ULL,
+ 0x74ba1df480803a80ULL, 0x997c6127bebec2beULL, 0x26de87ebcdcd13cdULL,
+ 0xbde468893434d034ULL, 0x7a75903248483d48ULL, 0xab24e354ffffdbffULL,
+ 0xf78ff48d7a7af57aULL, 0xf4ea3d6490907a90ULL, 0xc23ebe9d5f5f615fULL,
+ 0x1da0403d20208020ULL, 0x67d5d00f6868bd68ULL, 0xd07234ca1a1a681aULL,
+ 0x192c41b7aeae82aeULL, 0xc95e757db4b4eab4ULL, 0x9a19a8ce54544d54ULL,
+ 0xece53b7f93937693ULL, 0x0daa442f22228822ULL, 0x07e9c86364648d64ULL,
+ 0xdb12ff2af1f1e3f1ULL, 0xbfa2e6cc7373d173ULL, 0x905a248212124812ULL,
+ 0x3a5d807a40401d40ULL, 0x4028104808082008ULL, 0x56e89b95c3c32bc3ULL,
+ 0x337bc5dfecec97ecULL, 0x9690ab4ddbdb4bdbULL, 0x611f5fc0a1a1bea1ULL,
+ 0x1c8307918d8d0e8dULL, 0xf5c97ac83d3df43dULL, 0xccf1335b97976697ULL,
+ 0x0000000000000000ULL, 0x36d483f9cfcf1bcfULL, 0x4587566e2b2bac2bULL,
+ 0x97b3ece17676c576ULL, 0x64b019e682823282ULL, 0xfea9b128d6d67fd6ULL,
+ 0xd87736c31b1b6c1bULL, 0xc15b7774b5b5eeb5ULL, 0x112943beafaf86afULL,
+ 0x77dfd41d6a6ab56aULL, 0xba0da0ea50505d50ULL, 0x124c8a5745450945ULL,
+ 0xcb18fb38f3f3ebf3ULL, 0x9df060ad3030c030ULL, 0x2b74c3c4efef9befULL,
+ 0xe5c37eda3f3ffc3fULL, 0x921caac755554955ULL, 0x791059dba2a2b2a2ULL,
+ 0x0365c9e9eaea8feaULL, 0x0fecca6a65658965ULL, 0xb9686903babad2baULL,
+ 0x65935e4a2f2fbc2fULL, 0x4ee79d8ec0c027c0ULL, 0xbe81a160dede5fdeULL,
+ 0xe06c38fc1c1c701cULL, 0xbb2ee746fdfdd3fdULL, 0x52649a1f4d4d294dULL,
+ 0xe4e0397692927292ULL, 0x8fbceafa7575c975ULL, 0x301e0c3606061806ULL,
+ 0x249809ae8a8a128aULL, 0xf940794bb2b2f2b2ULL, 0x6359d185e6e6bfe6ULL,
+ 0x70361c7e0e0e380eULL, 0xf8633ee71f1f7c1fULL, 0x37f7c45562629562ULL,
+ 0xeea3b53ad4d477d4ULL, 0x29324d81a8a89aa8ULL, 0xc4f4315296966296ULL,
+ 0x9b3aef62f9f9c3f9ULL, 0x66f697a3c5c533c5ULL, 0x35b14a1025259425ULL,
+ 0xf220b2ab59597959ULL, 0x54ae15d084842a84ULL, 0xb7a7e4c57272d572ULL,
+ 0xd5dd72ec3939e439ULL, 0x5a6198164c4c2d4cULL, 0xca3bbc945e5e655eULL,
+ 0xe785f09f7878fd78ULL, 0xddd870e53838e038ULL, 0x148605988c8c0a8cULL,
+ 0xc6b2bf17d1d163d1ULL, 0x410b57e4a5a5aea5ULL, 0x434dd9a1e2e2afe2ULL,
+ 0x2ff8c24e61619961ULL, 0xf1457b42b3b3f6b3ULL, 0x15a5423421218421ULL,
+ 0x94d625089c9c4a9cULL, 0xf0663cee1e1e781eULL, 0x2252866143431143ULL,
+ 0x76fc93b1c7c73bc7ULL, 0xb32be54ffcfcd7fcULL, 0x2014082404041004ULL,
+ 0xb208a2e351515951ULL, 0xbcc72f2599995e99ULL, 0x4fc4da226d6da96dULL,
+ 0x68391a650d0d340dULL, 0x8335e979fafacffaULL, 0xb684a369dfdf5bdfULL,
+ 0xd79bfca97e7ee57eULL, 0x3db4481924249024ULL, 0xc5d776fe3b3bec3bULL,
+ 0x313d4b9aabab96abULL, 0x3ed181f0cece1fceULL, 0x8855229911114411ULL,
+ 0x0c8903838f8f068fULL, 0x4a6b9c044e4e254eULL, 0xd1517366b7b7e6b7ULL,
+ 0x0b60cbe0ebeb8bebULL, 0xfdcc78c13c3cf03cULL, 0x7cbf1ffd81813e81ULL,
+ 0xd4fe354094946a94ULL, 0xeb0cf31cf7f7fbf7ULL, 0xa1676f18b9b9deb9ULL,
+ 0x985f268b13134c13ULL, 0x7d9c58512c2cb02cULL, 0xd6b8bb05d3d36bd3ULL,
+ 0x6b5cd38ce7e7bbe7ULL, 0x57cbdc396e6ea56eULL, 0x6ef395aac4c437c4ULL,
+ 0x180f061b03030c03ULL, 0x8a13acdc56564556ULL, 0x1a49885e44440d44ULL,
+ 0xdf9efea07f7fe17fULL, 0x21374f88a9a99ea9ULL, 0x4d8254672a2aa82aULL,
+ 0xb16d6b0abbbbd6bbULL, 0x46e29f87c1c123c1ULL, 0xa202a6f153535153ULL,
+ 0xae8ba572dcdc57dcULL, 0x582716530b0b2c0bULL, 0x9cd327019d9d4e9dULL,
+ 0x47c1d82b6c6cad6cULL, 0x95f562a43131c431ULL, 0x87b9e8f37474cd74ULL,
+ 0xe309f115f6f6fff6ULL, 0x0a438c4c46460546ULL, 0x092645a5acac8aacULL,
+ 0x3c970fb589891e89ULL, 0xa04428b414145014ULL, 0x5b42dfbae1e1a3e1ULL,
+ 0xb04e2ca616165816ULL, 0xcdd274f73a3ae83aULL, 0x6fd0d2066969b969ULL,
+ 0x482d124109092409ULL, 0xa7ade0d77070dd70ULL, 0xd954716fb6b6e2b6ULL,
+ 0xceb7bd1ed0d067d0ULL, 0x3b7ec7d6eded93edULL, 0x2edb85e2cccc17ccULL,
+ 0x2a57846842421542ULL, 0xb4c22d2c98985a98ULL, 0x490e55eda4a4aaa4ULL,
+ 0x5d8850752828a028ULL, 0xda31b8865c5c6d5cULL, 0x933fed6bf8f8c7f8ULL,
+ 0x44a411c286862286ULL,
+};
+
+static const u64 C5[256] = {
+ 0x18c07830d8181860ULL, 0x2305af462623238cULL, 0xc67ef991b8c6c63fULL,
+ 0xe8136fcdfbe8e887ULL, 0x874ca113cb878726ULL, 0xb8a9626d11b8b8daULL,
+ 0x0108050209010104ULL, 0x4f426e9e0d4f4f21ULL, 0x36adee6c9b3636d8ULL,
+ 0xa6590451ffa6a6a2ULL, 0xd2debdb90cd2d26fULL, 0xf5fb06f70ef5f5f3ULL,
+ 0x79ef80f2967979f9ULL, 0x6f5fcede306f6fa1ULL, 0x91fcef3f6d91917eULL,
+ 0x52aa07a4f8525255ULL, 0x6027fdc04760609dULL, 0xbc89766535bcbccaULL,
+ 0x9baccd2b379b9b56ULL, 0x8e048c018a8e8e02ULL, 0xa371155bd2a3a3b6ULL,
+ 0x0c603c186c0c0c30ULL, 0x7bff8af6847b7bf1ULL, 0x35b5e16a803535d4ULL,
+ 0x1de8693af51d1d74ULL, 0xe05347ddb3e0e0a7ULL, 0xd7f6acb321d7d77bULL,
+ 0xc25eed999cc2c22fULL, 0x2e6d965c432e2eb8ULL, 0x4b627a96294b4b31ULL,
+ 0xfea321e15dfefedfULL, 0x578216aed5575741ULL, 0x15a8412abd151554ULL,
+ 0x779fb6eee87777c1ULL, 0x37a5eb6e923737dcULL, 0xe57b56d79ee5e5b3ULL,
+ 0x9f8cd923139f9f46ULL, 0xf0d317fd23f0f0e7ULL, 0x4a6a7f94204a4a35ULL,
+ 0xda9e95a944dada4fULL, 0x58fa25b0a258587dULL, 0xc906ca8fcfc9c903ULL,
+ 0x29558d527c2929a4ULL, 0x0a5022145a0a0a28ULL, 0xb1e14f7f50b1b1feULL,
+ 0xa0691a5dc9a0a0baULL, 0x6b7fdad6146b6bb1ULL, 0x855cab17d985852eULL,
+ 0xbd8173673cbdbdceULL, 0x5dd234ba8f5d5d69ULL, 0x1080502090101040ULL,
+ 0xf4f303f507f4f4f7ULL, 0xcb16c08bddcbcb0bULL, 0x3eedc67cd33e3ef8ULL,
+ 0x0528110a2d050514ULL, 0x671fe6ce78676781ULL, 0xe47353d597e4e4b7ULL,
+ 0x2725bb4e0227279cULL, 0x4132588273414119ULL, 0x8b2c9d0ba78b8b16ULL,
+ 0xa7510153f6a7a7a6ULL, 0x7dcf94fab27d7de9ULL, 0x95dcfb374995956eULL,
+ 0xd88e9fad56d8d847ULL, 0xfb8b30eb70fbfbcbULL, 0xee2371c1cdeeee9fULL,
+ 0x7cc791f8bb7c7cedULL, 0x6617e3cc71666685ULL, 0xdda68ea77bdddd53ULL,
+ 0x17b84b2eaf17175cULL, 0x4702468e45474701ULL, 0x9e84dc211a9e9e42ULL,
+ 0xca1ec589d4caca0fULL, 0x2d75995a582d2db4ULL, 0xbf9179632ebfbfc6ULL,
+ 0x07381b0e3f07071cULL, 0xad012347acadad8eULL, 0x5aea2fb4b05a5a75ULL,
+ 0x836cb51bef838336ULL, 0x3385ff66b63333ccULL, 0x633ff2c65c636391ULL,
+ 0x02100a0412020208ULL, 0xaa39384993aaaa92ULL, 0x71afa8e2de7171d9ULL,
+ 0xc80ecf8dc6c8c807ULL, 0x19c87d32d1191964ULL, 0x497270923b494939ULL,
+ 0xd9869aaf5fd9d943ULL, 0xf2c31df931f2f2efULL, 0xe34b48dba8e3e3abULL,
+ 0x5be22ab6b95b5b71ULL, 0x8834920dbc88881aULL, 0x9aa4c8293e9a9a52ULL,
+ 0x262dbe4c0b262698ULL, 0x328dfa64bf3232c8ULL, 0xb0e94a7d59b0b0faULL,
+ 0xe91b6acff2e9e983ULL, 0x0f78331e770f0f3cULL, 0xd5e6a6b733d5d573ULL,
+ 0x8074ba1df480803aULL, 0xbe997c6127bebec2ULL, 0xcd26de87ebcdcd13ULL,
+ 0x34bde468893434d0ULL, 0x487a75903248483dULL, 0xffab24e354ffffdbULL,
+ 0x7af78ff48d7a7af5ULL, 0x90f4ea3d6490907aULL, 0x5fc23ebe9d5f5f61ULL,
+ 0x201da0403d202080ULL, 0x6867d5d00f6868bdULL, 0x1ad07234ca1a1a68ULL,
+ 0xae192c41b7aeae82ULL, 0xb4c95e757db4b4eaULL, 0x549a19a8ce54544dULL,
+ 0x93ece53b7f939376ULL, 0x220daa442f222288ULL, 0x6407e9c86364648dULL,
+ 0xf1db12ff2af1f1e3ULL, 0x73bfa2e6cc7373d1ULL, 0x12905a2482121248ULL,
+ 0x403a5d807a40401dULL, 0x0840281048080820ULL, 0xc356e89b95c3c32bULL,
+ 0xec337bc5dfecec97ULL, 0xdb9690ab4ddbdb4bULL, 0xa1611f5fc0a1a1beULL,
+ 0x8d1c8307918d8d0eULL, 0x3df5c97ac83d3df4ULL, 0x97ccf1335b979766ULL,
+ 0x0000000000000000ULL, 0xcf36d483f9cfcf1bULL, 0x2b4587566e2b2bacULL,
+ 0x7697b3ece17676c5ULL, 0x8264b019e6828232ULL, 0xd6fea9b128d6d67fULL,
+ 0x1bd87736c31b1b6cULL, 0xb5c15b7774b5b5eeULL, 0xaf112943beafaf86ULL,
+ 0x6a77dfd41d6a6ab5ULL, 0x50ba0da0ea50505dULL, 0x45124c8a57454509ULL,
+ 0xf3cb18fb38f3f3ebULL, 0x309df060ad3030c0ULL, 0xef2b74c3c4efef9bULL,
+ 0x3fe5c37eda3f3ffcULL, 0x55921caac7555549ULL, 0xa2791059dba2a2b2ULL,
+ 0xea0365c9e9eaea8fULL, 0x650fecca6a656589ULL, 0xbab9686903babad2ULL,
+ 0x2f65935e4a2f2fbcULL, 0xc04ee79d8ec0c027ULL, 0xdebe81a160dede5fULL,
+ 0x1ce06c38fc1c1c70ULL, 0xfdbb2ee746fdfdd3ULL, 0x4d52649a1f4d4d29ULL,
+ 0x92e4e03976929272ULL, 0x758fbceafa7575c9ULL, 0x06301e0c36060618ULL,
+ 0x8a249809ae8a8a12ULL, 0xb2f940794bb2b2f2ULL, 0xe66359d185e6e6bfULL,
+ 0x0e70361c7e0e0e38ULL, 0x1ff8633ee71f1f7cULL, 0x6237f7c455626295ULL,
+ 0xd4eea3b53ad4d477ULL, 0xa829324d81a8a89aULL, 0x96c4f43152969662ULL,
+ 0xf99b3aef62f9f9c3ULL, 0xc566f697a3c5c533ULL, 0x2535b14a10252594ULL,
+ 0x59f220b2ab595979ULL, 0x8454ae15d084842aULL, 0x72b7a7e4c57272d5ULL,
+ 0x39d5dd72ec3939e4ULL, 0x4c5a6198164c4c2dULL, 0x5eca3bbc945e5e65ULL,
+ 0x78e785f09f7878fdULL, 0x38ddd870e53838e0ULL, 0x8c148605988c8c0aULL,
+ 0xd1c6b2bf17d1d163ULL, 0xa5410b57e4a5a5aeULL, 0xe2434dd9a1e2e2afULL,
+ 0x612ff8c24e616199ULL, 0xb3f1457b42b3b3f6ULL, 0x2115a54234212184ULL,
+ 0x9c94d625089c9c4aULL, 0x1ef0663cee1e1e78ULL, 0x4322528661434311ULL,
+ 0xc776fc93b1c7c73bULL, 0xfcb32be54ffcfcd7ULL, 0x0420140824040410ULL,
+ 0x51b208a2e3515159ULL, 0x99bcc72f2599995eULL, 0x6d4fc4da226d6da9ULL,
+ 0x0d68391a650d0d34ULL, 0xfa8335e979fafacfULL, 0xdfb684a369dfdf5bULL,
+ 0x7ed79bfca97e7ee5ULL, 0x243db44819242490ULL, 0x3bc5d776fe3b3becULL,
+ 0xab313d4b9aabab96ULL, 0xce3ed181f0cece1fULL, 0x1188552299111144ULL,
+ 0x8f0c8903838f8f06ULL, 0x4e4a6b9c044e4e25ULL, 0xb7d1517366b7b7e6ULL,
+ 0xeb0b60cbe0ebeb8bULL, 0x3cfdcc78c13c3cf0ULL, 0x817cbf1ffd81813eULL,
+ 0x94d4fe354094946aULL, 0xf7eb0cf31cf7f7fbULL, 0xb9a1676f18b9b9deULL,
+ 0x13985f268b13134cULL, 0x2c7d9c58512c2cb0ULL, 0xd3d6b8bb05d3d36bULL,
+ 0xe76b5cd38ce7e7bbULL, 0x6e57cbdc396e6ea5ULL, 0xc46ef395aac4c437ULL,
+ 0x03180f061b03030cULL, 0x568a13acdc565645ULL, 0x441a49885e44440dULL,
+ 0x7fdf9efea07f7fe1ULL, 0xa921374f88a9a99eULL, 0x2a4d8254672a2aa8ULL,
+ 0xbbb16d6b0abbbbd6ULL, 0xc146e29f87c1c123ULL, 0x53a202a6f1535351ULL,
+ 0xdcae8ba572dcdc57ULL, 0x0b582716530b0b2cULL, 0x9d9cd327019d9d4eULL,
+ 0x6c47c1d82b6c6cadULL, 0x3195f562a43131c4ULL, 0x7487b9e8f37474cdULL,
+ 0xf6e309f115f6f6ffULL, 0x460a438c4c464605ULL, 0xac092645a5acac8aULL,
+ 0x893c970fb589891eULL, 0x14a04428b4141450ULL, 0xe15b42dfbae1e1a3ULL,
+ 0x16b04e2ca6161658ULL, 0x3acdd274f73a3ae8ULL, 0x696fd0d2066969b9ULL,
+ 0x09482d1241090924ULL, 0x70a7ade0d77070ddULL, 0xb6d954716fb6b6e2ULL,
+ 0xd0ceb7bd1ed0d067ULL, 0xed3b7ec7d6eded93ULL, 0xcc2edb85e2cccc17ULL,
+ 0x422a578468424215ULL, 0x98b4c22d2c98985aULL, 0xa4490e55eda4a4aaULL,
+ 0x285d8850752828a0ULL, 0x5cda31b8865c5c6dULL, 0xf8933fed6bf8f8c7ULL,
+ 0x8644a411c2868622ULL,
+};
+
+static const u64 C6[256] = {
+ 0x6018c07830d81818ULL, 0x8c2305af46262323ULL, 0x3fc67ef991b8c6c6ULL,
+ 0x87e8136fcdfbe8e8ULL, 0x26874ca113cb8787ULL, 0xdab8a9626d11b8b8ULL,
+ 0x0401080502090101ULL, 0x214f426e9e0d4f4fULL, 0xd836adee6c9b3636ULL,
+ 0xa2a6590451ffa6a6ULL, 0x6fd2debdb90cd2d2ULL, 0xf3f5fb06f70ef5f5ULL,
+ 0xf979ef80f2967979ULL, 0xa16f5fcede306f6fULL, 0x7e91fcef3f6d9191ULL,
+ 0x5552aa07a4f85252ULL, 0x9d6027fdc0476060ULL, 0xcabc89766535bcbcULL,
+ 0x569baccd2b379b9bULL, 0x028e048c018a8e8eULL, 0xb6a371155bd2a3a3ULL,
+ 0x300c603c186c0c0cULL, 0xf17bff8af6847b7bULL, 0xd435b5e16a803535ULL,
+ 0x741de8693af51d1dULL, 0xa7e05347ddb3e0e0ULL, 0x7bd7f6acb321d7d7ULL,
+ 0x2fc25eed999cc2c2ULL, 0xb82e6d965c432e2eULL, 0x314b627a96294b4bULL,
+ 0xdffea321e15dfefeULL, 0x41578216aed55757ULL, 0x5415a8412abd1515ULL,
+ 0xc1779fb6eee87777ULL, 0xdc37a5eb6e923737ULL, 0xb3e57b56d79ee5e5ULL,
+ 0x469f8cd923139f9fULL, 0xe7f0d317fd23f0f0ULL, 0x354a6a7f94204a4aULL,
+ 0x4fda9e95a944dadaULL, 0x7d58fa25b0a25858ULL, 0x03c906ca8fcfc9c9ULL,
+ 0xa429558d527c2929ULL, 0x280a5022145a0a0aULL, 0xfeb1e14f7f50b1b1ULL,
+ 0xbaa0691a5dc9a0a0ULL, 0xb16b7fdad6146b6bULL, 0x2e855cab17d98585ULL,
+ 0xcebd8173673cbdbdULL, 0x695dd234ba8f5d5dULL, 0x4010805020901010ULL,
+ 0xf7f4f303f507f4f4ULL, 0x0bcb16c08bddcbcbULL, 0xf83eedc67cd33e3eULL,
+ 0x140528110a2d0505ULL, 0x81671fe6ce786767ULL, 0xb7e47353d597e4e4ULL,
+ 0x9c2725bb4e022727ULL, 0x1941325882734141ULL, 0x168b2c9d0ba78b8bULL,
+ 0xa6a7510153f6a7a7ULL, 0xe97dcf94fab27d7dULL, 0x6e95dcfb37499595ULL,
+ 0x47d88e9fad56d8d8ULL, 0xcbfb8b30eb70fbfbULL, 0x9fee2371c1cdeeeeULL,
+ 0xed7cc791f8bb7c7cULL, 0x856617e3cc716666ULL, 0x53dda68ea77bddddULL,
+ 0x5c17b84b2eaf1717ULL, 0x014702468e454747ULL, 0x429e84dc211a9e9eULL,
+ 0x0fca1ec589d4cacaULL, 0xb42d75995a582d2dULL, 0xc6bf9179632ebfbfULL,
+ 0x1c07381b0e3f0707ULL, 0x8ead012347acadadULL, 0x755aea2fb4b05a5aULL,
+ 0x36836cb51bef8383ULL, 0xcc3385ff66b63333ULL, 0x91633ff2c65c6363ULL,
+ 0x0802100a04120202ULL, 0x92aa39384993aaaaULL, 0xd971afa8e2de7171ULL,
+ 0x07c80ecf8dc6c8c8ULL, 0x6419c87d32d11919ULL, 0x39497270923b4949ULL,
+ 0x43d9869aaf5fd9d9ULL, 0xeff2c31df931f2f2ULL, 0xabe34b48dba8e3e3ULL,
+ 0x715be22ab6b95b5bULL, 0x1a8834920dbc8888ULL, 0x529aa4c8293e9a9aULL,
+ 0x98262dbe4c0b2626ULL, 0xc8328dfa64bf3232ULL, 0xfab0e94a7d59b0b0ULL,
+ 0x83e91b6acff2e9e9ULL, 0x3c0f78331e770f0fULL, 0x73d5e6a6b733d5d5ULL,
+ 0x3a8074ba1df48080ULL, 0xc2be997c6127bebeULL, 0x13cd26de87ebcdcdULL,
+ 0xd034bde468893434ULL, 0x3d487a7590324848ULL, 0xdbffab24e354ffffULL,
+ 0xf57af78ff48d7a7aULL, 0x7a90f4ea3d649090ULL, 0x615fc23ebe9d5f5fULL,
+ 0x80201da0403d2020ULL, 0xbd6867d5d00f6868ULL, 0x681ad07234ca1a1aULL,
+ 0x82ae192c41b7aeaeULL, 0xeab4c95e757db4b4ULL, 0x4d549a19a8ce5454ULL,
+ 0x7693ece53b7f9393ULL, 0x88220daa442f2222ULL, 0x8d6407e9c8636464ULL,
+ 0xe3f1db12ff2af1f1ULL, 0xd173bfa2e6cc7373ULL, 0x4812905a24821212ULL,
+ 0x1d403a5d807a4040ULL, 0x2008402810480808ULL, 0x2bc356e89b95c3c3ULL,
+ 0x97ec337bc5dfececULL, 0x4bdb9690ab4ddbdbULL, 0xbea1611f5fc0a1a1ULL,
+ 0x0e8d1c8307918d8dULL, 0xf43df5c97ac83d3dULL, 0x6697ccf1335b9797ULL,
+ 0x0000000000000000ULL, 0x1bcf36d483f9cfcfULL, 0xac2b4587566e2b2bULL,
+ 0xc57697b3ece17676ULL, 0x328264b019e68282ULL, 0x7fd6fea9b128d6d6ULL,
+ 0x6c1bd87736c31b1bULL, 0xeeb5c15b7774b5b5ULL, 0x86af112943beafafULL,
+ 0xb56a77dfd41d6a6aULL, 0x5d50ba0da0ea5050ULL, 0x0945124c8a574545ULL,
+ 0xebf3cb18fb38f3f3ULL, 0xc0309df060ad3030ULL, 0x9bef2b74c3c4efefULL,
+ 0xfc3fe5c37eda3f3fULL, 0x4955921caac75555ULL, 0xb2a2791059dba2a2ULL,
+ 0x8fea0365c9e9eaeaULL, 0x89650fecca6a6565ULL, 0xd2bab9686903babaULL,
+ 0xbc2f65935e4a2f2fULL, 0x27c04ee79d8ec0c0ULL, 0x5fdebe81a160dedeULL,
+ 0x701ce06c38fc1c1cULL, 0xd3fdbb2ee746fdfdULL, 0x294d52649a1f4d4dULL,
+ 0x7292e4e039769292ULL, 0xc9758fbceafa7575ULL, 0x1806301e0c360606ULL,
+ 0x128a249809ae8a8aULL, 0xf2b2f940794bb2b2ULL, 0xbfe66359d185e6e6ULL,
+ 0x380e70361c7e0e0eULL, 0x7c1ff8633ee71f1fULL, 0x956237f7c4556262ULL,
+ 0x77d4eea3b53ad4d4ULL, 0x9aa829324d81a8a8ULL, 0x6296c4f431529696ULL,
+ 0xc3f99b3aef62f9f9ULL, 0x33c566f697a3c5c5ULL, 0x942535b14a102525ULL,
+ 0x7959f220b2ab5959ULL, 0x2a8454ae15d08484ULL, 0xd572b7a7e4c57272ULL,
+ 0xe439d5dd72ec3939ULL, 0x2d4c5a6198164c4cULL, 0x655eca3bbc945e5eULL,
+ 0xfd78e785f09f7878ULL, 0xe038ddd870e53838ULL, 0x0a8c148605988c8cULL,
+ 0x63d1c6b2bf17d1d1ULL, 0xaea5410b57e4a5a5ULL, 0xafe2434dd9a1e2e2ULL,
+ 0x99612ff8c24e6161ULL, 0xf6b3f1457b42b3b3ULL, 0x842115a542342121ULL,
+ 0x4a9c94d625089c9cULL, 0x781ef0663cee1e1eULL, 0x1143225286614343ULL,
+ 0x3bc776fc93b1c7c7ULL, 0xd7fcb32be54ffcfcULL, 0x1004201408240404ULL,
+ 0x5951b208a2e35151ULL, 0x5e99bcc72f259999ULL, 0xa96d4fc4da226d6dULL,
+ 0x340d68391a650d0dULL, 0xcffa8335e979fafaULL, 0x5bdfb684a369dfdfULL,
+ 0xe57ed79bfca97e7eULL, 0x90243db448192424ULL, 0xec3bc5d776fe3b3bULL,
+ 0x96ab313d4b9aababULL, 0x1fce3ed181f0ceceULL, 0x4411885522991111ULL,
+ 0x068f0c8903838f8fULL, 0x254e4a6b9c044e4eULL, 0xe6b7d1517366b7b7ULL,
+ 0x8beb0b60cbe0ebebULL, 0xf03cfdcc78c13c3cULL, 0x3e817cbf1ffd8181ULL,
+ 0x6a94d4fe35409494ULL, 0xfbf7eb0cf31cf7f7ULL, 0xdeb9a1676f18b9b9ULL,
+ 0x4c13985f268b1313ULL, 0xb02c7d9c58512c2cULL, 0x6bd3d6b8bb05d3d3ULL,
+ 0xbbe76b5cd38ce7e7ULL, 0xa56e57cbdc396e6eULL, 0x37c46ef395aac4c4ULL,
+ 0x0c03180f061b0303ULL, 0x45568a13acdc5656ULL, 0x0d441a49885e4444ULL,
+ 0xe17fdf9efea07f7fULL, 0x9ea921374f88a9a9ULL, 0xa82a4d8254672a2aULL,
+ 0xd6bbb16d6b0abbbbULL, 0x23c146e29f87c1c1ULL, 0x5153a202a6f15353ULL,
+ 0x57dcae8ba572dcdcULL, 0x2c0b582716530b0bULL, 0x4e9d9cd327019d9dULL,
+ 0xad6c47c1d82b6c6cULL, 0xc43195f562a43131ULL, 0xcd7487b9e8f37474ULL,
+ 0xfff6e309f115f6f6ULL, 0x05460a438c4c4646ULL, 0x8aac092645a5acacULL,
+ 0x1e893c970fb58989ULL, 0x5014a04428b41414ULL, 0xa3e15b42dfbae1e1ULL,
+ 0x5816b04e2ca61616ULL, 0xe83acdd274f73a3aULL, 0xb9696fd0d2066969ULL,
+ 0x2409482d12410909ULL, 0xdd70a7ade0d77070ULL, 0xe2b6d954716fb6b6ULL,
+ 0x67d0ceb7bd1ed0d0ULL, 0x93ed3b7ec7d6ededULL, 0x17cc2edb85e2ccccULL,
+ 0x15422a5784684242ULL, 0x5a98b4c22d2c9898ULL, 0xaaa4490e55eda4a4ULL,
+ 0xa0285d8850752828ULL, 0x6d5cda31b8865c5cULL, 0xc7f8933fed6bf8f8ULL,
+ 0x228644a411c28686ULL,
+};
+
+static const u64 C7[256] = {
+ 0x186018c07830d818ULL, 0x238c2305af462623ULL, 0xc63fc67ef991b8c6ULL,
+ 0xe887e8136fcdfbe8ULL, 0x8726874ca113cb87ULL, 0xb8dab8a9626d11b8ULL,
+ 0x0104010805020901ULL, 0x4f214f426e9e0d4fULL, 0x36d836adee6c9b36ULL,
+ 0xa6a2a6590451ffa6ULL, 0xd26fd2debdb90cd2ULL, 0xf5f3f5fb06f70ef5ULL,
+ 0x79f979ef80f29679ULL, 0x6fa16f5fcede306fULL, 0x917e91fcef3f6d91ULL,
+ 0x525552aa07a4f852ULL, 0x609d6027fdc04760ULL, 0xbccabc89766535bcULL,
+ 0x9b569baccd2b379bULL, 0x8e028e048c018a8eULL, 0xa3b6a371155bd2a3ULL,
+ 0x0c300c603c186c0cULL, 0x7bf17bff8af6847bULL, 0x35d435b5e16a8035ULL,
+ 0x1d741de8693af51dULL, 0xe0a7e05347ddb3e0ULL, 0xd77bd7f6acb321d7ULL,
+ 0xc22fc25eed999cc2ULL, 0x2eb82e6d965c432eULL, 0x4b314b627a96294bULL,
+ 0xfedffea321e15dfeULL, 0x5741578216aed557ULL, 0x155415a8412abd15ULL,
+ 0x77c1779fb6eee877ULL, 0x37dc37a5eb6e9237ULL, 0xe5b3e57b56d79ee5ULL,
+ 0x9f469f8cd923139fULL, 0xf0e7f0d317fd23f0ULL, 0x4a354a6a7f94204aULL,
+ 0xda4fda9e95a944daULL, 0x587d58fa25b0a258ULL, 0xc903c906ca8fcfc9ULL,
+ 0x29a429558d527c29ULL, 0x0a280a5022145a0aULL, 0xb1feb1e14f7f50b1ULL,
+ 0xa0baa0691a5dc9a0ULL, 0x6bb16b7fdad6146bULL, 0x852e855cab17d985ULL,
+ 0xbdcebd8173673cbdULL, 0x5d695dd234ba8f5dULL, 0x1040108050209010ULL,
+ 0xf4f7f4f303f507f4ULL, 0xcb0bcb16c08bddcbULL, 0x3ef83eedc67cd33eULL,
+ 0x05140528110a2d05ULL, 0x6781671fe6ce7867ULL, 0xe4b7e47353d597e4ULL,
+ 0x279c2725bb4e0227ULL, 0x4119413258827341ULL, 0x8b168b2c9d0ba78bULL,
+ 0xa7a6a7510153f6a7ULL, 0x7de97dcf94fab27dULL, 0x956e95dcfb374995ULL,
+ 0xd847d88e9fad56d8ULL, 0xfbcbfb8b30eb70fbULL, 0xee9fee2371c1cdeeULL,
+ 0x7ced7cc791f8bb7cULL, 0x66856617e3cc7166ULL, 0xdd53dda68ea77bddULL,
+ 0x175c17b84b2eaf17ULL, 0x47014702468e4547ULL, 0x9e429e84dc211a9eULL,
+ 0xca0fca1ec589d4caULL, 0x2db42d75995a582dULL, 0xbfc6bf9179632ebfULL,
+ 0x071c07381b0e3f07ULL, 0xad8ead012347acadULL, 0x5a755aea2fb4b05aULL,
+ 0x8336836cb51bef83ULL, 0x33cc3385ff66b633ULL, 0x6391633ff2c65c63ULL,
+ 0x020802100a041202ULL, 0xaa92aa39384993aaULL, 0x71d971afa8e2de71ULL,
+ 0xc807c80ecf8dc6c8ULL, 0x196419c87d32d119ULL, 0x4939497270923b49ULL,
+ 0xd943d9869aaf5fd9ULL, 0xf2eff2c31df931f2ULL, 0xe3abe34b48dba8e3ULL,
+ 0x5b715be22ab6b95bULL, 0x881a8834920dbc88ULL, 0x9a529aa4c8293e9aULL,
+ 0x2698262dbe4c0b26ULL, 0x32c8328dfa64bf32ULL, 0xb0fab0e94a7d59b0ULL,
+ 0xe983e91b6acff2e9ULL, 0x0f3c0f78331e770fULL, 0xd573d5e6a6b733d5ULL,
+ 0x803a8074ba1df480ULL, 0xbec2be997c6127beULL, 0xcd13cd26de87ebcdULL,
+ 0x34d034bde4688934ULL, 0x483d487a75903248ULL, 0xffdbffab24e354ffULL,
+ 0x7af57af78ff48d7aULL, 0x907a90f4ea3d6490ULL, 0x5f615fc23ebe9d5fULL,
+ 0x2080201da0403d20ULL, 0x68bd6867d5d00f68ULL, 0x1a681ad07234ca1aULL,
+ 0xae82ae192c41b7aeULL, 0xb4eab4c95e757db4ULL, 0x544d549a19a8ce54ULL,
+ 0x937693ece53b7f93ULL, 0x2288220daa442f22ULL, 0x648d6407e9c86364ULL,
+ 0xf1e3f1db12ff2af1ULL, 0x73d173bfa2e6cc73ULL, 0x124812905a248212ULL,
+ 0x401d403a5d807a40ULL, 0x0820084028104808ULL, 0xc32bc356e89b95c3ULL,
+ 0xec97ec337bc5dfecULL, 0xdb4bdb9690ab4ddbULL, 0xa1bea1611f5fc0a1ULL,
+ 0x8d0e8d1c8307918dULL, 0x3df43df5c97ac83dULL, 0x976697ccf1335b97ULL,
+ 0x0000000000000000ULL, 0xcf1bcf36d483f9cfULL, 0x2bac2b4587566e2bULL,
+ 0x76c57697b3ece176ULL, 0x82328264b019e682ULL, 0xd67fd6fea9b128d6ULL,
+ 0x1b6c1bd87736c31bULL, 0xb5eeb5c15b7774b5ULL, 0xaf86af112943beafULL,
+ 0x6ab56a77dfd41d6aULL, 0x505d50ba0da0ea50ULL, 0x450945124c8a5745ULL,
+ 0xf3ebf3cb18fb38f3ULL, 0x30c0309df060ad30ULL, 0xef9bef2b74c3c4efULL,
+ 0x3ffc3fe5c37eda3fULL, 0x554955921caac755ULL, 0xa2b2a2791059dba2ULL,
+ 0xea8fea0365c9e9eaULL, 0x6589650fecca6a65ULL, 0xbad2bab9686903baULL,
+ 0x2fbc2f65935e4a2fULL, 0xc027c04ee79d8ec0ULL, 0xde5fdebe81a160deULL,
+ 0x1c701ce06c38fc1cULL, 0xfdd3fdbb2ee746fdULL, 0x4d294d52649a1f4dULL,
+ 0x927292e4e0397692ULL, 0x75c9758fbceafa75ULL, 0x061806301e0c3606ULL,
+ 0x8a128a249809ae8aULL, 0xb2f2b2f940794bb2ULL, 0xe6bfe66359d185e6ULL,
+ 0x0e380e70361c7e0eULL, 0x1f7c1ff8633ee71fULL, 0x62956237f7c45562ULL,
+ 0xd477d4eea3b53ad4ULL, 0xa89aa829324d81a8ULL, 0x966296c4f4315296ULL,
+ 0xf9c3f99b3aef62f9ULL, 0xc533c566f697a3c5ULL, 0x25942535b14a1025ULL,
+ 0x597959f220b2ab59ULL, 0x842a8454ae15d084ULL, 0x72d572b7a7e4c572ULL,
+ 0x39e439d5dd72ec39ULL, 0x4c2d4c5a6198164cULL, 0x5e655eca3bbc945eULL,
+ 0x78fd78e785f09f78ULL, 0x38e038ddd870e538ULL, 0x8c0a8c148605988cULL,
+ 0xd163d1c6b2bf17d1ULL, 0xa5aea5410b57e4a5ULL, 0xe2afe2434dd9a1e2ULL,
+ 0x6199612ff8c24e61ULL, 0xb3f6b3f1457b42b3ULL, 0x21842115a5423421ULL,
+ 0x9c4a9c94d625089cULL, 0x1e781ef0663cee1eULL, 0x4311432252866143ULL,
+ 0xc73bc776fc93b1c7ULL, 0xfcd7fcb32be54ffcULL, 0x0410042014082404ULL,
+ 0x515951b208a2e351ULL, 0x995e99bcc72f2599ULL, 0x6da96d4fc4da226dULL,
+ 0x0d340d68391a650dULL, 0xfacffa8335e979faULL, 0xdf5bdfb684a369dfULL,
+ 0x7ee57ed79bfca97eULL, 0x2490243db4481924ULL, 0x3bec3bc5d776fe3bULL,
+ 0xab96ab313d4b9aabULL, 0xce1fce3ed181f0ceULL, 0x1144118855229911ULL,
+ 0x8f068f0c8903838fULL, 0x4e254e4a6b9c044eULL, 0xb7e6b7d1517366b7ULL,
+ 0xeb8beb0b60cbe0ebULL, 0x3cf03cfdcc78c13cULL, 0x813e817cbf1ffd81ULL,
+ 0x946a94d4fe354094ULL, 0xf7fbf7eb0cf31cf7ULL, 0xb9deb9a1676f18b9ULL,
+ 0x134c13985f268b13ULL, 0x2cb02c7d9c58512cULL, 0xd36bd3d6b8bb05d3ULL,
+ 0xe7bbe76b5cd38ce7ULL, 0x6ea56e57cbdc396eULL, 0xc437c46ef395aac4ULL,
+ 0x030c03180f061b03ULL, 0x5645568a13acdc56ULL, 0x440d441a49885e44ULL,
+ 0x7fe17fdf9efea07fULL, 0xa99ea921374f88a9ULL, 0x2aa82a4d8254672aULL,
+ 0xbbd6bbb16d6b0abbULL, 0xc123c146e29f87c1ULL, 0x535153a202a6f153ULL,
+ 0xdc57dcae8ba572dcULL, 0x0b2c0b582716530bULL, 0x9d4e9d9cd327019dULL,
+ 0x6cad6c47c1d82b6cULL, 0x31c43195f562a431ULL, 0x74cd7487b9e8f374ULL,
+ 0xf6fff6e309f115f6ULL, 0x4605460a438c4c46ULL, 0xac8aac092645a5acULL,
+ 0x891e893c970fb589ULL, 0x145014a04428b414ULL, 0xe1a3e15b42dfbae1ULL,
+ 0x165816b04e2ca616ULL, 0x3ae83acdd274f73aULL, 0x69b9696fd0d20669ULL,
+ 0x092409482d124109ULL, 0x70dd70a7ade0d770ULL, 0xb6e2b6d954716fb6ULL,
+ 0xd067d0ceb7bd1ed0ULL, 0xed93ed3b7ec7d6edULL, 0xcc17cc2edb85e2ccULL,
+ 0x4215422a57846842ULL, 0x985a98b4c22d2c98ULL, 0xa4aaa4490e55eda4ULL,
+ 0x28a0285d88507528ULL, 0x5c6d5cda31b8865cULL, 0xf8c7f8933fed6bf8ULL,
+ 0x86228644a411c286ULL,
+};
+
+static const u64 rc[WHIRLPOOL_ROUNDS + 1] = {
+ 0x0000000000000000ULL, 0x1823c6e887b8014fULL, 0x36a6d2f5796f9152ULL,
+ 0x60bc9b8ea30c7b35ULL, 0x1de0d7c22e4bfe57ULL, 0x157737e59ff04adaULL,
+ 0x58c9290ab1a06b85ULL, 0xbd5d10f4cb3e0567ULL, 0xe427418ba77d95d8ULL,
+ 0xfbee7c66dd17479eULL, 0xca2dbf07ad5a8333ULL,
+};
+
+/**
+ * The core Whirlpool transform.
+ */
+
+static void whirlpool_process_buffer(struct whirlpool_ctx *wctx) {
+ int i, r;
+ u64 K[8]; /* the round key */
+ u64 block[8]; /* mu(buffer) */
+ u64 state[8]; /* the cipher state */
+ u64 L[8];
+ u8 *buffer = wctx->buffer;
+
+ for (i = 0; i < 8; i++, buffer += 8) {
+ block[i] =
+ (((u64)buffer[0] ) << 56) ^
+ (((u64)buffer[1] & 0xffL) << 48) ^
+ (((u64)buffer[2] & 0xffL) << 40) ^
+ (((u64)buffer[3] & 0xffL) << 32) ^
+ (((u64)buffer[4] & 0xffL) << 24) ^
+ (((u64)buffer[5] & 0xffL) << 16) ^
+ (((u64)buffer[6] & 0xffL) << 8) ^
+ (((u64)buffer[7] & 0xffL) );
+ }
+
+ state[0] = block[0] ^ (K[0] = wctx->hash[0]);
+ state[1] = block[1] ^ (K[1] = wctx->hash[1]);
+ state[2] = block[2] ^ (K[2] = wctx->hash[2]);
+ state[3] = block[3] ^ (K[3] = wctx->hash[3]);
+ state[4] = block[4] ^ (K[4] = wctx->hash[4]);
+ state[5] = block[5] ^ (K[5] = wctx->hash[5]);
+ state[6] = block[6] ^ (K[6] = wctx->hash[6]);
+ state[7] = block[7] ^ (K[7] = wctx->hash[7]);
+
+ for (r = 1; r <= WHIRLPOOL_ROUNDS; r++) {
+
+ L[0] = C0[(int)(K[0] >> 56) ] ^
+ C1[(int)(K[7] >> 48) & 0xff] ^
+ C2[(int)(K[6] >> 40) & 0xff] ^
+ C3[(int)(K[5] >> 32) & 0xff] ^
+ C4[(int)(K[4] >> 24) & 0xff] ^
+ C5[(int)(K[3] >> 16) & 0xff] ^
+ C6[(int)(K[2] >> 8) & 0xff] ^
+ C7[(int)(K[1] ) & 0xff] ^
+ rc[r];
+
+ L[1] = C0[(int)(K[1] >> 56) ] ^
+ C1[(int)(K[0] >> 48) & 0xff] ^
+ C2[(int)(K[7] >> 40) & 0xff] ^
+ C3[(int)(K[6] >> 32) & 0xff] ^
+ C4[(int)(K[5] >> 24) & 0xff] ^
+ C5[(int)(K[4] >> 16) & 0xff] ^
+ C6[(int)(K[3] >> 8) & 0xff] ^
+ C7[(int)(K[2] ) & 0xff];
+
+ L[2] = C0[(int)(K[2] >> 56) ] ^
+ C1[(int)(K[1] >> 48) & 0xff] ^
+ C2[(int)(K[0] >> 40) & 0xff] ^
+ C3[(int)(K[7] >> 32) & 0xff] ^
+ C4[(int)(K[6] >> 24) & 0xff] ^
+ C5[(int)(K[5] >> 16) & 0xff] ^
+ C6[(int)(K[4] >> 8) & 0xff] ^
+ C7[(int)(K[3] ) & 0xff];
+
+ L[3] = C0[(int)(K[3] >> 56) ] ^
+ C1[(int)(K[2] >> 48) & 0xff] ^
+ C2[(int)(K[1] >> 40) & 0xff] ^
+ C3[(int)(K[0] >> 32) & 0xff] ^
+ C4[(int)(K[7] >> 24) & 0xff] ^
+ C5[(int)(K[6] >> 16) & 0xff] ^
+ C6[(int)(K[5] >> 8) & 0xff] ^
+ C7[(int)(K[4] ) & 0xff];
+
+ L[4] = C0[(int)(K[4] >> 56) ] ^
+ C1[(int)(K[3] >> 48) & 0xff] ^
+ C2[(int)(K[2] >> 40) & 0xff] ^
+ C3[(int)(K[1] >> 32) & 0xff] ^
+ C4[(int)(K[0] >> 24) & 0xff] ^
+ C5[(int)(K[7] >> 16) & 0xff] ^
+ C6[(int)(K[6] >> 8) & 0xff] ^
+ C7[(int)(K[5] ) & 0xff];
+
+ L[5] = C0[(int)(K[5] >> 56) ] ^
+ C1[(int)(K[4] >> 48) & 0xff] ^
+ C2[(int)(K[3] >> 40) & 0xff] ^
+ C3[(int)(K[2] >> 32) & 0xff] ^
+ C4[(int)(K[1] >> 24) & 0xff] ^
+ C5[(int)(K[0] >> 16) & 0xff] ^
+ C6[(int)(K[7] >> 8) & 0xff] ^
+ C7[(int)(K[6] ) & 0xff];
+
+ L[6] = C0[(int)(K[6] >> 56) ] ^
+ C1[(int)(K[5] >> 48) & 0xff] ^
+ C2[(int)(K[4] >> 40) & 0xff] ^
+ C3[(int)(K[3] >> 32) & 0xff] ^
+ C4[(int)(K[2] >> 24) & 0xff] ^
+ C5[(int)(K[1] >> 16) & 0xff] ^
+ C6[(int)(K[0] >> 8) & 0xff] ^
+ C7[(int)(K[7] ) & 0xff];
+
+ L[7] = C0[(int)(K[7] >> 56) ] ^
+ C1[(int)(K[6] >> 48) & 0xff] ^
+ C2[(int)(K[5] >> 40) & 0xff] ^
+ C3[(int)(K[4] >> 32) & 0xff] ^
+ C4[(int)(K[3] >> 24) & 0xff] ^
+ C5[(int)(K[2] >> 16) & 0xff] ^
+ C6[(int)(K[1] >> 8) & 0xff] ^
+ C7[(int)(K[0] ) & 0xff];
+
+ K[0] = L[0];
+ K[1] = L[1];
+ K[2] = L[2];
+ K[3] = L[3];
+ K[4] = L[4];
+ K[5] = L[5];
+ K[6] = L[6];
+ K[7] = L[7];
+
+ L[0] = C0[(int)(state[0] >> 56) ] ^
+ C1[(int)(state[7] >> 48) & 0xff] ^
+ C2[(int)(state[6] >> 40) & 0xff] ^
+ C3[(int)(state[5] >> 32) & 0xff] ^
+ C4[(int)(state[4] >> 24) & 0xff] ^
+ C5[(int)(state[3] >> 16) & 0xff] ^
+ C6[(int)(state[2] >> 8) & 0xff] ^
+ C7[(int)(state[1] ) & 0xff] ^
+ K[0];
+
+ L[1] = C0[(int)(state[1] >> 56) ] ^
+ C1[(int)(state[0] >> 48) & 0xff] ^
+ C2[(int)(state[7] >> 40) & 0xff] ^
+ C3[(int)(state[6] >> 32) & 0xff] ^
+ C4[(int)(state[5] >> 24) & 0xff] ^
+ C5[(int)(state[4] >> 16) & 0xff] ^
+ C6[(int)(state[3] >> 8) & 0xff] ^
+ C7[(int)(state[2] ) & 0xff] ^
+ K[1];
+
+ L[2] = C0[(int)(state[2] >> 56) ] ^
+ C1[(int)(state[1] >> 48) & 0xff] ^
+ C2[(int)(state[0] >> 40) & 0xff] ^
+ C3[(int)(state[7] >> 32) & 0xff] ^
+ C4[(int)(state[6] >> 24) & 0xff] ^
+ C5[(int)(state[5] >> 16) & 0xff] ^
+ C6[(int)(state[4] >> 8) & 0xff] ^
+ C7[(int)(state[3] ) & 0xff] ^
+ K[2];
+
+ L[3] = C0[(int)(state[3] >> 56) ] ^
+ C1[(int)(state[2] >> 48) & 0xff] ^
+ C2[(int)(state[1] >> 40) & 0xff] ^
+ C3[(int)(state[0] >> 32) & 0xff] ^
+ C4[(int)(state[7] >> 24) & 0xff] ^
+ C5[(int)(state[6] >> 16) & 0xff] ^
+ C6[(int)(state[5] >> 8) & 0xff] ^
+ C7[(int)(state[4] ) & 0xff] ^
+ K[3];
+
+ L[4] = C0[(int)(state[4] >> 56) ] ^
+ C1[(int)(state[3] >> 48) & 0xff] ^
+ C2[(int)(state[2] >> 40) & 0xff] ^
+ C3[(int)(state[1] >> 32) & 0xff] ^
+ C4[(int)(state[0] >> 24) & 0xff] ^
+ C5[(int)(state[7] >> 16) & 0xff] ^
+ C6[(int)(state[6] >> 8) & 0xff] ^
+ C7[(int)(state[5] ) & 0xff] ^
+ K[4];
+
+ L[5] = C0[(int)(state[5] >> 56) ] ^
+ C1[(int)(state[4] >> 48) & 0xff] ^
+ C2[(int)(state[3] >> 40) & 0xff] ^
+ C3[(int)(state[2] >> 32) & 0xff] ^
+ C4[(int)(state[1] >> 24) & 0xff] ^
+ C5[(int)(state[0] >> 16) & 0xff] ^
+ C6[(int)(state[7] >> 8) & 0xff] ^
+ C7[(int)(state[6] ) & 0xff] ^
+ K[5];
+
+ L[6] = C0[(int)(state[6] >> 56) ] ^
+ C1[(int)(state[5] >> 48) & 0xff] ^
+ C2[(int)(state[4] >> 40) & 0xff] ^
+ C3[(int)(state[3] >> 32) & 0xff] ^
+ C4[(int)(state[2] >> 24) & 0xff] ^
+ C5[(int)(state[1] >> 16) & 0xff] ^
+ C6[(int)(state[0] >> 8) & 0xff] ^
+ C7[(int)(state[7] ) & 0xff] ^
+ K[6];
+
+ L[7] = C0[(int)(state[7] >> 56) ] ^
+ C1[(int)(state[6] >> 48) & 0xff] ^
+ C2[(int)(state[5] >> 40) & 0xff] ^
+ C3[(int)(state[4] >> 32) & 0xff] ^
+ C4[(int)(state[3] >> 24) & 0xff] ^
+ C5[(int)(state[2] >> 16) & 0xff] ^
+ C6[(int)(state[1] >> 8) & 0xff] ^
+ C7[(int)(state[0] ) & 0xff] ^
+ K[7];
+
+ state[0] = L[0];
+ state[1] = L[1];
+ state[2] = L[2];
+ state[3] = L[3];
+ state[4] = L[4];
+ state[5] = L[5];
+ state[6] = L[6];
+ state[7] = L[7];
+ }
+ /*
+ * apply the Miyaguchi-Preneel compression function:
+ */
+ wctx->hash[0] ^= state[0] ^ block[0];
+ wctx->hash[1] ^= state[1] ^ block[1];
+ wctx->hash[2] ^= state[2] ^ block[2];
+ wctx->hash[3] ^= state[3] ^ block[3];
+ wctx->hash[4] ^= state[4] ^ block[4];
+ wctx->hash[5] ^= state[5] ^ block[5];
+ wctx->hash[6] ^= state[6] ^ block[6];
+ wctx->hash[7] ^= state[7] ^ block[7];
+
+}
+
+static void whirlpool_init (void *ctx) {
+ int i;
+ struct whirlpool_ctx *wctx = ctx;
+
+ memset(wctx->bitLength, 0, 32);
+ wctx->bufferBits = wctx->bufferPos = 0;
+ wctx->buffer[0] = 0;
+ for (i = 0; i < 8; i++) {
+ wctx->hash[i] = 0L;
+ }
+}
+
+static void whirlpool_update(void *ctx, const u8 *source, unsigned int len)
+{
+
+ struct whirlpool_ctx *wctx = ctx;
+ int sourcePos = 0;
+ unsigned int bits_len = len * 8; // convert to number of bits
+ int sourceGap = (8 - ((int)bits_len & 7)) & 7;
+ int bufferRem = wctx->bufferBits & 7;
+ int i;
+ u32 b, carry;
+ u8 *buffer = wctx->buffer;
+ u8 *bitLength = wctx->bitLength;
+ int bufferBits = wctx->bufferBits;
+ int bufferPos = wctx->bufferPos;
+
+ u64 value = bits_len;
+ for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) {
+ carry += bitLength[i] + ((u32)value & 0xff);
+ bitLength[i] = (u8)carry;
+ carry >>= 8;
+ value >>= 8;
+ }
+ while (bits_len > 8) {
+ b = ((source[sourcePos] << sourceGap) & 0xff) |
+ ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
+ buffer[bufferPos++] |= (u8)(b >> bufferRem);
+ bufferBits += 8 - bufferRem;
+ if (bufferBits == WHIRLPOOL_DIGEST_SIZE * 8) {
+ whirlpool_process_buffer(wctx);
+ bufferBits = bufferPos = 0;
+ }
+ buffer[bufferPos] = b << (8 - bufferRem);
+ bufferBits += bufferRem;
+ bits_len -= 8;
+ sourcePos++;
+ }
+ if (bits_len > 0) {
+ b = (source[sourcePos] << sourceGap) & 0xff;
+ buffer[bufferPos] |= b >> bufferRem;
+ } else {
+ b = 0;
+ }
+ if (bufferRem + bits_len < 8) {
+ bufferBits += bits_len;
+ } else {
+ bufferPos++;
+ bufferBits += 8 - bufferRem;
+ bits_len -= 8 - bufferRem;
+ if (bufferBits == WHIRLPOOL_DIGEST_SIZE * 8) {
+ whirlpool_process_buffer(wctx);
+ bufferBits = bufferPos = 0;
+ }
+ buffer[bufferPos] = b << (8 - bufferRem);
+ bufferBits += (int)bits_len;
+ }
+
+ wctx->bufferBits = bufferBits;
+ wctx->bufferPos = bufferPos;
+
+}
+
+static void whirlpool_final(void *ctx, u8 *out)
+{
+ struct whirlpool_ctx *wctx = ctx;
+ int i;
+ u8 *buffer = wctx->buffer;
+ u8 *bitLength = wctx->bitLength;
+ int bufferBits = wctx->bufferBits;
+ int bufferPos = wctx->bufferPos;
+ u8 *digest = out;
+
+ buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
+ bufferPos++;
+ if (bufferPos > WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES) {
+ if (bufferPos < WHIRLPOOL_BLOCK_SIZE) {
+ memset(&buffer[bufferPos], 0, WHIRLPOOL_BLOCK_SIZE - bufferPos);
+ }
+ whirlpool_process_buffer(wctx);
+ bufferPos = 0;
+ }
+ if (bufferPos < WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES) {
+ memset(&buffer[bufferPos], 0,
+ (WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES) - bufferPos);
+ }
+ bufferPos = WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES;
+ memcpy(&buffer[WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES],
+ bitLength, WHIRLPOOL_LENGTHBYTES);
+ whirlpool_process_buffer(wctx);
+ for (i = 0; i < WHIRLPOOL_DIGEST_SIZE/8; i++) {
+ digest[0] = (u8)(wctx->hash[i] >> 56);
+ digest[1] = (u8)(wctx->hash[i] >> 48);
+ digest[2] = (u8)(wctx->hash[i] >> 40);
+ digest[3] = (u8)(wctx->hash[i] >> 32);
+ digest[4] = (u8)(wctx->hash[i] >> 24);
+ digest[5] = (u8)(wctx->hash[i] >> 16);
+ digest[6] = (u8)(wctx->hash[i] >> 8);
+ digest[7] = (u8)(wctx->hash[i] );
+ digest += 8;
+ }
+ wctx->bufferBits = bufferBits;
+ wctx->bufferPos = bufferPos;
+}
+
+static struct crypto_alg alg = {
+ .cra_name = "whirlpool",
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = WHIRLPOOL_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct whirlpool_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(alg.cra_list),
+ .cra_u = { .digest = {
+ .dia_digestsize = WHIRLPOOL_DIGEST_SIZE,
+ .dia_init = whirlpool_init,
+ .dia_update = whirlpool_update,
+ .dia_final = whirlpool_final } }
+};
+
+static int __init init(void)
+{
+ return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+ crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm");
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index b2bede5407821..2ceed3ba0f73c 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3681,18 +3681,25 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
struct idt77252_dev *card;
struct atm_dev *dev;
ushort revision = 0;
- int i;
+ int i, err;
+
+ if (pci_enable_device(pcidev)) {
+ printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev));
+ return -ENODEV;
+ }
if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) {
printk("idt77252-%d: can't read PCI_REVISION_ID\n", index);
- return -ENODEV;
+ err = -ENODEV;
+ goto err_out_disable_pdev;
}
card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
if (!card) {
printk("idt77252-%d: can't allocate private data\n", index);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_out_disable_pdev;
}
memset(card, 0, sizeof(struct idt77252_dev));
@@ -3718,23 +3725,21 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
card->membase = (unsigned long) ioremap(membase, 1024);
if (!card->membase) {
printk("%s: can't ioremap() membase\n", card->name);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_free_card;
}
if (idt77252_preset(card)) {
printk("%s: preset failed\n", card->name);
- iounmap((void *) card->membase);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_iounmap;
}
dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL);
if (!dev) {
printk("%s: can't register atm device\n", card->name);
- iounmap((void *) card->membase);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_iounmap;
}
dev->dev_data = card;
card->atmdev = dev;
@@ -3743,9 +3748,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
suni_init(dev);
if (!dev->phy) {
printk("%s: can't init SUNI\n", card->name);
- deinit_card(card);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_deinit_card;
}
#endif /* CONFIG_ATM_IDT77252_USE_SUNI */
@@ -3756,9 +3760,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
ioremap(srambase | 0x200000 | (i << 18), 4);
if (!card->fbq[i]) {
printk("%s: can't ioremap() FBQ%d\n", card->name, i);
- deinit_card(card);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_deinit_card;
}
}
@@ -3769,9 +3772,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
if (init_card(dev)) {
printk("%s: init_card failed\n", card->name);
- deinit_card(card);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_deinit_card;
}
dev->ci_range.vpi_bits = card->vpibits;
@@ -3783,12 +3785,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
if (idt77252_dev_open(card)) {
printk("%s: dev_open failed\n", card->name);
-
- if (dev->phy->stop)
- dev->phy->stop(dev);
- deinit_card(card);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_stop;
}
*last = card;
@@ -3796,6 +3794,23 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
index++;
return 0;
+
+err_out_stop:
+ if (dev->phy->stop)
+ dev->phy->stop(dev);
+
+err_out_deinit_card:
+ deinit_card(card);
+
+err_out_iounmap:
+ iounmap((void *) card->membase);
+
+err_out_free_card:
+ kfree(card);
+
+err_out_disable_pdev:
+ pci_disable_device(pcidev);
+ return err;
}
static struct pci_device_id idt77252_pci_tbl[] =
@@ -3848,6 +3863,7 @@ static void __exit idt77252_exit(void)
if (dev->phy->stop)
dev->phy->stop(dev);
deinit_card(card);
+ pci_disable_device(card->pcidev);
kfree(card);
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 2693bb5455f4f..70be974509c3d 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -349,14 +349,19 @@ void class_device_initialize(struct class_device *class_dev)
int class_device_add(struct class_device *class_dev)
{
- struct class * parent;
+ struct class * parent = NULL;
struct class_interface * class_intf;
int error;
class_dev = class_device_get(class_dev);
- if (!class_dev || !strlen(class_dev->class_id))
+ if (!class_dev)
return -EINVAL;
+ if (!strlen(class_dev->class_id)) {
+ error = -EINVAL;
+ goto register_done;
+ }
+
parent = class_get(class_dev->class);
pr_debug("CLASS: registering class device: ID = '%s'\n",
diff --git a/drivers/base/node.c b/drivers/base/node.c
index c1187363fca82..df74785efa5f1 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -19,7 +19,7 @@ static struct sysdev_class node_class = {
static ssize_t node_read_cpumap(struct sys_device * dev, char * buf)
{
struct node *node_dev = to_node(dev);
- cpumask_t mask = node_dev->cpumap;
+ cpumask_t mask = node_to_cpumask(node_dev->sysdev.id);
int len;
/* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */
@@ -38,11 +38,19 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
int n;
int nid = dev->id;
struct sysinfo i;
+ unsigned long inactive;
+ unsigned long active;
+ unsigned long free;
+
si_meminfo_node(&i, nid);
+ __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
+
n = sprintf(buf, "\n"
"Node %d MemTotal: %8lu kB\n"
"Node %d MemFree: %8lu kB\n"
"Node %d MemUsed: %8lu kB\n"
+ "Node %d Active: %8lu kB\n"
+ "Node %d Inactive: %8lu kB\n"
"Node %d HighTotal: %8lu kB\n"
"Node %d HighFree: %8lu kB\n"
"Node %d LowTotal: %8lu kB\n"
@@ -50,6 +58,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
nid, K(i.totalram),
nid, K(i.freeram),
nid, K(i.totalram - i.freeram),
+ nid, K(active),
+ nid, K(inactive),
nid, K(i.totalhigh),
nid, K(i.freehigh),
nid, K(i.totalram - i.totalhigh),
@@ -111,7 +121,6 @@ int __init register_node(struct node *node, int num, struct node *parent)
{
int error;
- node->cpumap = node_to_cpumask(num);
node->sysdev.id = num;
node->sysdev.cls = &node_class;
error = sysdev_register(&node->sysdev);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index fe8332e340f9c..b3c7f07c16fd8 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -349,13 +349,17 @@ static int rd_open(struct inode *inode, struct file *filp)
if (rd_bdev[unit] == NULL) {
struct block_device *bdev = inode->i_bdev;
struct address_space *mapping;
+ unsigned bsize;
int gfp_mask;
inode = igrab(bdev->bd_inode);
rd_bdev[unit] = bdev;
bdev->bd_openers++;
- bdev->bd_block_size = rd_blocksize;
- inode->i_size = get_capacity(rd_disks[unit])<<9;
+ bsize = bdev_hardsect_size(bdev);
+ bdev->bd_block_size = bsize;
+ inode->i_blkbits = blksize_bits(bsize);
+ inode->i_size = get_capacity(bdev->bd_disk)<<9;
+
mapping = inode->i_mapping;
mapping->a_ops = &ramdisk_aops;
mapping->backing_dev_info = &rd_backing_dev_info;
@@ -449,6 +453,7 @@ static int __init rd_init(void)
goto out_queue;
blk_queue_make_request(rd_queue[i], &rd_make_request);
+ blk_queue_hardsect_size(rd_queue[i], rd_blocksize);
/* rd_size is given in kB */
disk->major = RAMDISK_MAJOR;
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
index 134305d148e3e..c1d2877d0974a 100644
--- a/drivers/block/scsi_ioctl.c
+++ b/drivers/block/scsi_ioctl.c
@@ -178,6 +178,7 @@ static int verify_command(struct file *file, unsigned char *cmd)
safe_for_write(GPCMD_SEND_EVENT),
safe_for_write(GPCMD_SEND_KEY),
safe_for_write(GPCMD_SEND_OPC),
+ safe_for_write(GPCMD_SEND_CUE_SHEET),
safe_for_write(GPCMD_SET_SPEED),
safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL),
safe_for_write(GPCMD_LOAD_UNLOAD),
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 292c4507b60d0..382030453332e 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -7,8 +7,11 @@
#
FONTMAPFILE = cp437.uni
-obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o
+obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
+obj-$(CONFIG_LEGACY_PTYS) += pty.o
+obj-$(CONFIG_UNIX98_PTYS) += pty.o
+obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \
consolemap_deftbl.o selection.o keyboard.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 3dc61d41b33d3..03bd20eaeda5e 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -430,7 +430,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
- printk("ttyS%02d CD now %s...", info->line,
+ printk("ttyS%d CD now %s...", info->line,
(!(status & SER_DCD)) ? "on" : "off");
#endif
if (!(status & SER_DCD))
@@ -2095,7 +2095,7 @@ static int __init rs_init(void)
continue;
*/
- printk(KERN_INFO "ttyS%02d is the amiga builtin serial port\n",
+ printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
state->line);
/* Hardware set up */
diff --git a/drivers/char/ip2/ip2types.h b/drivers/char/ip2/ip2types.h
index 8d2b3799941a2..9d67b260b2f62 100644
--- a/drivers/char/ip2/ip2types.h
+++ b/drivers/char/ip2/ip2types.h
@@ -49,6 +49,9 @@ typedef struct
short irq[IP2_MAX_BOARDS];
unsigned short addr[IP2_MAX_BOARDS];
int type[IP2_MAX_BOARDS];
+#ifdef CONFIG_PCI
+ struct pci_dev *pci_dev[IP2_MAX_BOARDS];
+#endif
} ip2config_t;
#endif
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index ac97e617a1078..fa3ca6eb5d537 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -440,6 +440,12 @@ cleanup_module(void)
// free memory
for (i = 0; i < IP2_MAX_BOARDS; i++) {
void *pB;
+#ifdef CONFIG_PCI
+ if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
+ pci_disable_device(ip2config.pci_dev[i]);
+ ip2config.pci_dev[i] = NULL;
+ }
+#endif
if ((pB = i2BoardPtrTable[i]) != 0 ) {
kfree ( pB );
i2BoardPtrTable[i] = NULL;
@@ -594,9 +600,14 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
if (pci_dev_i != NULL) {
unsigned int addr;
- unsigned char pci_irq;
+ if (pci_enable_device(pci_dev_i)) {
+ printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
+ pci_name(pci_dev_i));
+ break;
+ }
ip2config.type[i] = PCI;
+ ip2config.pci_dev[i] = pci_dev_i;
status =
pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
if ( addr & 1 ) {
@@ -604,8 +615,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
} else {
printk( KERN_ERR "IP2: PCI I/O address error\n");
}
- status =
- pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
// If the PCI BIOS assigned it, lets try and use it. If we
// can't acquire it or it screws up, deal with it then.
@@ -614,7 +623,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
// pci_irq = 0;
// }
- ip2config.irq[i] = pci_irq;
+ ip2config.irq[i] = pci_dev_i->irq;
} else { // ann error
ip2config.addr[i] = 0;
if (status == PCIBIOS_DEVICE_NOT_FOUND) {
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index bb8544385d977..7e7503df71159 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -424,7 +424,7 @@ static void ipmi_po_new_smi(int if_num)
if (ready)
return;
- rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, 0, &ipmi_user);
+ rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user);
if (rv) {
printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
rv);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index cb1cfb0afd887..f0e765b5e20b5 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/pcmcia/synclink_cs.c
*
- * $Id: synclink_cs.c,v 4.22 2004/06/01 20:27:46 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $
*
* Device driver for Microgate SyncLink PC Card
* multiprotocol serial adapter.
@@ -68,6 +68,7 @@
#include <asm/types.h>
#include <linux/termios.h>
#include <linux/workqueue.h>
+#include <linux/hdlc.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
@@ -76,12 +77,8 @@
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
-#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
-#define CONFIG_SYNCLINK_SYNCPPP 1
-#endif
-
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-#include <net/syncppp.h>
+#ifdef CONFIG_HDLC_MODULE
+#define CONFIG_HDLC 1
#endif
#define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -239,12 +236,11 @@ typedef struct _mgslpc_info {
int netcount;
int dosyncppp;
spinlock_t netlock;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- struct ppp_device pppdev;
- char netname[10];
+
+#ifdef CONFIG_HDLC
struct net_device *netdev;
- struct net_device_stats netstats;
#endif
+
} MGSLPC_INFO;
#define MGSLPC_MAGIC 0x5402
@@ -262,7 +258,7 @@ typedef struct _mgslpc_info {
* FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it.
*/
#undef PVR
-
+
#define RXFIFO 0
#define TXFIFO 0
#define STAR 0x20
@@ -398,18 +394,12 @@ static void tx_timeout(unsigned long context);
static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-/* SPPP/HDLC stuff */
-static void mgslpc_sppp_init(MGSLPC_INFO *info);
-static void mgslpc_sppp_delete(MGSLPC_INFO *info);
-static int mgslpc_sppp_open(struct net_device *d);
-static int mgslpc_sppp_close(struct net_device *d);
-static void mgslpc_sppp_tx_timeout(struct net_device *d);
-static int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *d);
-static void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size);
-static void mgslpc_sppp_tx_done(MGSLPC_INFO *info);
-static int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-struct net_device_stats *mgslpc_net_stats(struct net_device *dev);
+#ifdef CONFIG_HDLC
+#define dev_to_port(D) (dev_to_hdlc(D)->priv)
+static void hdlcdev_tx_done(MGSLPC_INFO *info);
+static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size);
+static int hdlcdev_init(MGSLPC_INFO *info);
+static void hdlcdev_exit(MGSLPC_INFO *info);
#endif
static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit);
@@ -494,7 +484,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
MODULE_LICENSE("GPL");
static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.22 $";
+static char *driver_version = "$Revision: 4.26 $";
static struct tty_driver *serial_driver;
@@ -1163,9 +1153,9 @@ void tx_done(MGSLPC_INFO *info)
info->drop_rts_on_tx_done = 0;
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef CONFIG_HDLC
if (info->netcount)
- mgslpc_sppp_tx_done(info);
+ hdlcdev_tx_done(info);
else
#endif
{
@@ -1271,13 +1261,13 @@ void dcd_change(MGSLPC_INFO *info)
info->icount.dcd++;
if (info->serial_signals & SerialSignal_DCD) {
info->input_signal_events.dcd_up++;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount)
- sppp_reopen(info->netdev);
-#endif
}
else
info->input_signal_events.dcd_down++;
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev);
+#endif
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
@@ -2876,7 +2866,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
cleanup:
if (retval) {
if (tty->count == 1)
- info->tty = NULL;/* tty layer will release tty struct */
+ info->tty = NULL; /* tty layer will release tty struct */
if(info->count)
info->count--;
}
@@ -2931,7 +2921,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
if (info->icount.rxover)
ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
if (info->icount.rxcrc)
- ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);
+ ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
} else {
ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d",
info->icount.tx, info->icount.rx);
@@ -3070,12 +3060,8 @@ void mgslpc_add_device(MGSLPC_INFO *info)
printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n",
info->device_name, info->io_base, info->irq_level);
-
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-#ifdef MODULE
- if (info->dosyncppp)
-#endif
- mgslpc_sppp_init(info);
+#ifdef CONFIG_HDLC
+ hdlcdev_init(info);
#endif
}
@@ -3090,9 +3076,8 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
last->next_device = info->next_device;
else
mgslpc_device_list = info->next_device;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->dosyncppp)
- mgslpc_sppp_delete(info);
+#ifdef CONFIG_HDLC
+ hdlcdev_exit(info);
#endif
release_resources(info);
kfree(info);
@@ -4021,9 +4006,12 @@ int rx_get_frame(MGSLPC_INFO *info)
return_frame = 1;
}
framesize = 0;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- info->netstats.rx_errors++;
- info->netstats.rx_frame_errors++;
+#ifdef CONFIG_HDLC
+ {
+ struct net_device_stats *stats = hdlc_stats(info->netdev);
+ stats->rx_errors++;
+ stats->rx_frame_errors++;
+ }
#endif
} else
return_frame = 1;
@@ -4052,11 +4040,9 @@ int rx_get_frame(MGSLPC_INFO *info)
++framesize;
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount) {
- /* pass frame to syncppp device */
- mgslpc_sppp_rx_done(info, buf->data, framesize);
- }
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlcdev_rx(info, buf->data, framesize);
else
#endif
{
@@ -4215,88 +4201,134 @@ void tx_timeout(unsigned long context)
spin_unlock_irqrestore(&info->lock,flags);
-#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef CONFIG_HDLC
if (info->netcount)
- mgslpc_sppp_tx_done(info);
+ hdlcdev_tx_done(info);
else
#endif
bh_transmit(info);
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-/* syncppp net device routines
+#ifdef CONFIG_HDLC
+
+/**
+ * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
+ * set encoding and frame check sequence (FCS) options
+ *
+ * dev pointer to network device structure
+ * encoding serial encoding setting
+ * parity FCS setting
+ *
+ * returns 0 if success, otherwise error code
*/
-
-static void mgslpc_setup(struct net_device *dev)
+static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
+ unsigned short parity)
{
- dev->open = mgslpc_sppp_open;
- dev->stop = mgslpc_sppp_close;
- dev->hard_start_xmit = mgslpc_sppp_tx;
- dev->do_ioctl = mgslpc_sppp_ioctl;
- dev->get_stats = mgslpc_net_stats;
- dev->tx_timeout = mgslpc_sppp_tx_timeout;
- dev->watchdog_timeo = 10*HZ;
-}
+ MGSLPC_INFO *info = dev_to_port(dev);
+ unsigned char new_encoding;
+ unsigned short new_crctype;
-void mgslpc_sppp_init(MGSLPC_INFO *info)
-{
- struct net_device *d;
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
- sprintf(info->netname,"mgslp%d",info->line);
-
- d = alloc_netdev(0, info->netname, mgslpc_setup);
- if (!d) {
- printk(KERN_WARNING "%s: alloc_netdev failed.\n",
- info->netname);
- return;
+ switch (encoding)
+ {
+ case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break;
+ case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
+ case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
+ case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
+ case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
+ default: return -EINVAL;
}
- info->if_ptr = &info->pppdev;
- info->netdev = info->pppdev.dev = d;
-
- d->base_addr = info->io_base;
- d->irq = info->irq_level;
- d->priv = info;
+ switch (parity)
+ {
+ case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break;
+ case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
+ case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
+ default: return -EINVAL;
+ }
- sppp_attach(&info->pppdev);
- mgslpc_setup(d);
+ info->params.encoding = new_encoding;
+ info->params.crc_type = new_crctype;;
- if (register_netdev(d)) {
- printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
- sppp_detach(info->netdev);
- info->netdev = NULL;
- info->pppdev.dev = NULL;
- free_netdev(d);
- return;
- }
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ mgslpc_program_hw(info);
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_init()\n");
+ return 0;
}
-void mgslpc_sppp_delete(MGSLPC_INFO *info)
+/**
+ * called by generic HDLC layer to send frame
+ *
+ * skb socket buffer containing HDLC frame
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ MGSLPC_INFO *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
+ unsigned long flags;
+
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_delete(%s)\n",info->netname);
- unregister_netdev(info->netdev);
- sppp_detach(info->netdev);
- free_netdev(info->netdev);
- info->netdev = NULL;
- info->pppdev.dev = NULL;
+ printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name);
+
+ /* stop sending until this frame completes */
+ netif_stop_queue(dev);
+
+ /* copy data to device buffers */
+ memcpy(info->tx_buf, skb->data, skb->len);
+ info->tx_get = 0;
+ info->tx_put = info->tx_count = skb->len;
+
+ /* update network statistics */
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+
+ /* done with socket buffer, so free it */
+ dev_kfree_skb(skb);
+
+ /* save start time for transmit timeout detection */
+ dev->trans_start = jiffies;
+
+ /* start hardware transmitter if necessary */
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active)
+ tx_start(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ return 0;
}
-int mgslpc_sppp_open(struct net_device *d)
+/**
+ * called by network layer when interface enabled
+ * claim resources and initialize hardware
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_open(struct net_device *dev)
{
- MGSLPC_INFO *info = d->priv;
- int err;
+ MGSLPC_INFO *info = dev_to_port(dev);
+ int rc;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_open(%s)\n",info->netname);
+ printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
+
+ /* generic HDLC layer open processing */
+ if ((rc = hdlc_open(dev)))
+ return rc;
+ /* arbitrate between network and tty opens */
spin_lock_irqsave(&info->netlock, flags);
if (info->count != 0 || info->netcount != 0) {
- printk(KERN_WARNING "%s: sppp_open returning busy\n", info->netname);
+ printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
spin_unlock_irqrestore(&info->netlock, flags);
return -EBUSY;
}
@@ -4304,142 +4336,297 @@ int mgslpc_sppp_open(struct net_device *d)
spin_unlock_irqrestore(&info->netlock, flags);
/* claim resources and init adapter */
- if ((err = startup(info)) != 0)
- goto open_fail;
-
- /* allow syncppp module to do open processing */
- if ((err = sppp_open(d)) != 0) {
- shutdown(info);
- goto open_fail;
+ if ((rc = startup(info)) != 0) {
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+ return rc;
}
+ /* assert DTR and RTS, apply hardware settings */
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
mgslpc_program_hw(info);
- d->trans_start = jiffies;
- netif_start_queue(d);
- return 0;
+ /* enable network layer transmit */
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
-open_fail:
- spin_lock_irqsave(&info->netlock, flags);
- info->netcount=0;
- spin_unlock_irqrestore(&info->netlock, flags);
- return err;
+ /* inform generic HDLC layer of current DCD status */
+ spin_lock_irqsave(&info->lock, flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
+ hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
+
+ return 0;
}
-void mgslpc_sppp_tx_timeout(struct net_device *dev)
+/**
+ * called by network layer when interface is disabled
+ * shutdown hardware and release resources
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_close(struct net_device *dev)
{
- MGSLPC_INFO *info = dev->priv;
+ MGSLPC_INFO *info = dev_to_port(dev);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_tx_timeout(%s)\n",info->netname);
+ printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name);
- info->netstats.tx_errors++;
- info->netstats.tx_aborted_errors++;
+ netif_stop_queue(dev);
- spin_lock_irqsave(&info->lock,flags);
- tx_stop(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ /* shutdown adapter and release resources */
+ shutdown(info);
- netif_wake_queue(dev);
+ hdlc_close(dev);
+
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+
+ return 0;
}
-int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *dev)
+/**
+ * called by network layer to process IOCTL call to network device
+ *
+ * dev pointer to network device structure
+ * ifr pointer to network interface request structure
+ * cmd IOCTL command code
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- MGSLPC_INFO *info = dev->priv;
- unsigned long flags;
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ MGSLPC_INFO *info = dev_to_port(dev);
+ unsigned int flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_tx(%s)\n",info->netname);
+ printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
- netif_stop_queue(dev);
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
- info->tx_count = skb->len;
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
- memcpy(info->tx_buf, skb->data, skb->len);
- info->tx_get = 0;
- info->tx_put = info->tx_count = skb->len;
+ switch(ifr->ifr_settings.type) {
+ case IF_GET_IFACE: /* return current sync_serial_settings */
- info->netstats.tx_packets++;
- info->netstats.tx_bytes += skb->len;
- dev_kfree_skb(skb);
+ ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
- dev->trans_start = jiffies;
+ flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+
+ switch (flags){
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
+ case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
+ default: new_line.clock_type = CLOCK_DEFAULT;
+ }
- spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active)
- tx_start(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ new_line.clock_rate = info->params.clock_speed;
+ new_line.loopback = info->params.loopback ? 1:0;
- return 0;
+ if (copy_to_user(line, &new_line, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ switch (new_line.clock_type)
+ {
+ case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
+ case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
+ case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_DEFAULT: flags = info->params.flags &
+ (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break;
+ default: return -EINVAL;
+ }
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+ info->params.flags |= flags;
+
+ info->params.loopback = new_line.loopback;
+
+ if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
+ info->params.clock_speed = new_line.clock_rate;
+ else
+ info->params.clock_speed = 0;
+
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ mgslpc_program_hw(info);
+ return 0;
+
+ default:
+ return hdlc_ioctl(dev, ifr, cmd);
+ }
}
-int mgslpc_sppp_close(struct net_device *d)
+/**
+ * called by network layer when transmit timeout is detected
+ *
+ * dev pointer to network device structure
+ */
+static void hdlcdev_tx_timeout(struct net_device *dev)
{
- MGSLPC_INFO *info = d->priv;
+ MGSLPC_INFO *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_close(%s)\n",info->netname);
+ printk("hdlcdev_tx_timeout(%s)\n",dev->name);
- /* shutdown adapter and release resources */
- shutdown(info);
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
- /* allow syncppp to do close processing */
- sppp_close(d);
- netif_stop_queue(d);
+ spin_lock_irqsave(&info->lock,flags);
+ tx_stop(info);
+ spin_unlock_irqrestore(&info->lock,flags);
- spin_lock_irqsave(&info->netlock, flags);
- info->netcount=0;
- spin_unlock_irqrestore(&info->netlock, flags);
- return 0;
+ netif_wake_queue(dev);
+}
+
+/**
+ * called by device driver when transmit completes
+ * reenable network layer transmit if stopped
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_tx_done(MGSLPC_INFO *info)
+{
+ if (netif_queue_stopped(info->netdev))
+ netif_wake_queue(info->netdev);
}
-void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size)
+/**
+ * called by device driver when frame received
+ * pass frame to network layer
+ *
+ * info pointer to device instance information
+ * buf pointer to buffer contianing frame data
+ * size count of data bytes in buf
+ */
+static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size)
{
struct sk_buff *skb = dev_alloc_skb(size);
+ struct net_device *dev = info->netdev;
+ struct net_device_stats *stats = hdlc_stats(dev);
+
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_sppp_rx_done(%s)\n",info->netname);
+ printk("hdlcdev_rx(%s)\n",dev->name);
+
if (skb == NULL) {
- printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n",
- info->netname);
- info->netstats.rx_dropped++;
+ printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name);
+ stats->rx_dropped++;
return;
}
memcpy(skb_put(skb, size),buf,size);
- skb->protocol = htons(ETH_P_WAN_PPP);
- skb->dev = info->netdev;
- skb->mac.raw = skb->data;
- info->netstats.rx_packets++;
- info->netstats.rx_bytes += size;
+ skb->dev = info->netdev;
+ skb->mac.raw = skb->data;
+ skb->protocol = hdlc_type_trans(skb, skb->dev);
+
+ stats->rx_packets++;
+ stats->rx_bytes += size;
+
netif_rx(skb);
- info->netdev->trans_start = jiffies;
-}
-void mgslpc_sppp_tx_done(MGSLPC_INFO *info)
-{
- if (netif_queue_stopped(info->netdev))
- netif_wake_queue(info->netdev);
+ info->netdev->last_rx = jiffies;
}
-struct net_device_stats *mgslpc_net_stats(struct net_device *dev)
+/**
+ * called by device driver when adding device instance
+ * do generic HDLC initialization
+ *
+ * info pointer to device instance information
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_init(MGSLPC_INFO *info)
{
- MGSLPC_INFO *info = dev->priv;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgslpc_net_stats(%s)\n",info->netname);
- return &info->netstats;
+ int rc;
+ struct net_device *dev;
+ hdlc_device *hdlc;
+
+ /* allocate and initialize network and HDLC layer objects */
+
+ if (!(dev = alloc_hdlcdev(info))) {
+ printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
+ return -ENOMEM;
+ }
+
+ /* for network layer reporting purposes only */
+ dev->base_addr = info->io_base;
+ dev->irq = info->irq_level;
+
+ /* network layer callbacks and settings */
+ dev->do_ioctl = hdlcdev_ioctl;
+ dev->open = hdlcdev_open;
+ dev->stop = hdlcdev_close;
+ dev->tx_timeout = hdlcdev_tx_timeout;
+ dev->watchdog_timeo = 10*HZ;
+ dev->tx_queue_len = 50;
+
+ /* generic HDLC layer callbacks and settings */
+ hdlc = dev_to_hdlc(dev);
+ hdlc->attach = hdlcdev_attach;
+ hdlc->xmit = hdlcdev_xmit;
+
+ /* register objects with HDLC layer */
+ if ((rc = register_hdlc_device(dev))) {
+ printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
+ free_netdev(dev);
+ return rc;
+ }
+
+ info->netdev = dev;
+ return 0;
}
-int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/**
+ * called by device driver when removing device instance
+ * do generic HDLC cleanup
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_exit(MGSLPC_INFO *info)
{
- MGSLPC_INFO *info = dev->priv;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
- info->netname, cmd );
- return sppp_do_ioctl(dev, ifr, cmd);
+ unregister_hdlc_device(info->netdev);
+ free_netdev(info->netdev);
+ info->netdev = NULL;
}
-#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
+#endif /* CONFIG_HDLC */
+
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index fcbb325477e40..cac0e98639cf9 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -32,12 +32,6 @@
#include <asm/bitops.h>
#include <linux/devpts_fs.h>
-#if defined(CONFIG_LEGACY_PTYS) || defined(CONFIG_UNIX98_PTYS)
-
-#ifdef CONFIG_LEGACY_PTYS
-static struct tty_driver *pty_driver, *pty_slave_driver;
-#endif
-
/* These are global because they are accessed in tty_io.c */
#ifdef CONFIG_UNIX98_PTYS
struct tty_driver *ptm_driver;
@@ -205,19 +199,6 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
}
-/*
- * Return the device number of a Unix98 PTY (only!). This lets us open a
- * master pty with the multi-headed ptmx device, then find out which
- * one we got after it is open, with an ioctl.
- */
-#ifdef CONFIG_UNIX98_PTYS
-static int pty_get_device_number(struct tty_struct *tty, unsigned __user *value)
-{
- unsigned int result = tty->index;
- return put_user(result, value);
-}
-#endif
-
/* Set the lock flag on a pty */
static int pty_set_lock(struct tty_struct *tty, int __user * arg)
{
@@ -231,41 +212,6 @@ static int pty_set_lock(struct tty_struct *tty, int __user * arg)
return 0;
}
-#ifdef CONFIG_LEGACY_PTYS
-static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- if (!tty) {
- printk("pty_ioctl called with NULL tty!\n");
- return -EIO;
- }
- switch(cmd) {
- case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
- return pty_set_lock(tty, (int __user *) arg);
- }
- return -ENOIOCTLCMD;
-}
-#endif
-
-#ifdef CONFIG_UNIX98_PTYS
-static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- if (!tty) {
- printk("pty_unix98_ioctl called with NULL tty!\n");
- return -EIO;
- }
- switch(cmd) {
- case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
- return pty_set_lock(tty, (int __user *)arg);
- case TIOCGPTN: /* Get PT Number */
- return pty_get_device_number(tty, (unsigned int __user *)arg);
- }
-
- return -ENOIOCTLCMD;
-}
-#endif
-
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
@@ -322,42 +268,22 @@ static struct tty_operations pty_ops = {
.set_termios = pty_set_termios,
};
-/* sysctl support for setting limits on the number of Unix98 ptys allocated.
- Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */
-#ifdef CONFIG_UNIX98_PTYS
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+static struct tty_driver *pty_driver, *pty_slave_driver;
-ctl_table pty_table[] = {
- {
- .ctl_name = PTY_MAX,
- .procname = "max",
- .maxlen = sizeof(int),
- .mode = 0644,
- .data = &pty_limit,
- .proc_handler = &proc_dointvec_minmax,
- .strategy = &sysctl_intvec,
- .extra1 = &pty_limit_min,
- .extra2 = &pty_limit_max,
- }, {
- .ctl_name = PTY_NR,
- .procname = "nr",
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec,
- }, {
- .ctl_name = 0
+static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+ return pty_set_lock(tty, (int __user *) arg);
}
-};
-#endif
-
-/* Initialization */
+ return -ENOIOCTLCMD;
+}
-static int __init pty_init(void)
+static void __init legacy_pty_init(void)
{
-#ifdef CONFIG_LEGACY_PTYS
- /* Traditional BSD devices */
pty_driver = alloc_tty_driver(NR_PTYS);
if (!pty_driver)
@@ -404,11 +330,58 @@ static int __init pty_init(void)
panic("Couldn't register pty driver");
if (tty_register_driver(pty_slave_driver))
panic("Couldn't register pty slave driver");
+}
+#else
+static inline void legacy_pty_init(void) { }
+#endif
-#endif /* CONFIG_LEGACY_PTYS */
-
+/* Unix98 devices */
#ifdef CONFIG_UNIX98_PTYS
- /* Unix98 devices */
+/*
+ * sysctl support for setting limits on the number of Unix98 ptys allocated.
+ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
+ */
+int pty_limit = NR_UNIX98_PTY_DEFAULT;
+static int pty_limit_min = 0;
+static int pty_limit_max = NR_UNIX98_PTY_MAX;
+
+ctl_table pty_table[] = {
+ {
+ .ctl_name = PTY_MAX,
+ .procname = "max",
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .data = &pty_limit,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &pty_limit_min,
+ .extra2 = &pty_limit_max,
+ }, {
+ .ctl_name = PTY_NR,
+ .procname = "nr",
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = &proc_dointvec,
+ }, {
+ .ctl_name = 0
+ }
+};
+
+static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+ return pty_set_lock(tty, (int __user *)arg);
+ case TIOCGPTN: /* Get PT Number */
+ return put_user(tty->index, (unsigned int __user *)arg);
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static void __init unix98_pty_init(void)
+{
devfs_mk_dir("pts");
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
if (!ptm_driver)
@@ -455,10 +428,15 @@ static int __init pty_init(void)
panic("Couldn't register Unix98 pts driver");
pty_table[1].data = &ptm_driver->refcount;
-#endif /* CONFIG_UNIX98_PTYS */
+}
+#else
+static inline void unix98_pty_init(void) { }
+#endif
+static int __init pty_init(void)
+{
+ legacy_pty_init();
+ unix98_pty_init();
return 0;
}
module_init(pty_init);
-
-#endif /* CONFIG_LEGACY_PTYS || CONFIG_UNIX98_PTYS */
diff --git a/drivers/char/random.c b/drivers/char/random.c
index a162ddd65f152..f046cd1f2450c 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -401,6 +401,7 @@ static struct poolinfo {
*/
static struct entropy_store *random_state; /* The default global store */
static struct entropy_store *sec_random_state; /* secondary store */
+static struct entropy_store *urandom_state; /* For urandom */
static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
@@ -493,6 +494,7 @@ struct entropy_store {
/* mostly-read data: */
struct poolinfo poolinfo;
__u32 *pool;
+ const char *name;
/* read-write data: */
spinlock_t lock ____cacheline_aligned_in_smp;
@@ -507,7 +509,8 @@ struct entropy_store {
*
* Returns an negative error if there is a problem.
*/
-static int create_entropy_store(int size, struct entropy_store **ret_bucket)
+static int create_entropy_store(int size, const char *name,
+ struct entropy_store **ret_bucket)
{
struct entropy_store *r;
struct poolinfo *p;
@@ -538,6 +541,7 @@ static int create_entropy_store(int size, struct entropy_store **ret_bucket)
}
memset(r->pool, 0, POOLBYTES);
r->lock = SPIN_LOCK_UNLOCKED;
+ r->name = name;
*ret_bucket = r;
return 0;
}
@@ -643,12 +647,8 @@ static void credit_entropy_store(struct entropy_store *r, int nbits)
} else {
r->entropy_count += nbits;
if (nbits)
- DEBUG_ENT("%04d %04d : added %d bits to %s\n",
- random_state->entropy_count,
- sec_random_state->entropy_count,
- nbits,
- r == sec_random_state ? "secondary" :
- r == random_state ? "primary" : "unknown");
+ DEBUG_ENT("Added %d entropy credits to %s, now %d\n",
+ nbits, r->name, r->entropy_count);
}
spin_unlock_irqrestore(&r->lock, flags);
@@ -1328,8 +1328,7 @@ static inline void xfer_secondary_pool(struct entropy_store *r,
"(%d of %d requested)\n",
random_state->entropy_count,
sec_random_state->entropy_count,
- r == sec_random_state ? "secondary" : "unknown",
- bytes * 8, nbytes * 8, r->entropy_count);
+ r->name, bytes * 8, nbytes * 8, r->entropy_count);
bytes=extract_entropy(random_state, tmp, bytes,
EXTRACT_ENTROPY_LIMIT);
@@ -1373,9 +1372,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
DEBUG_ENT("%04d %04d : trying to extract %d bits from %s\n",
random_state->entropy_count,
sec_random_state->entropy_count,
- nbytes * 8,
- r == sec_random_state ? "secondary" :
- r == random_state ? "primary" : "unknown");
+ nbytes * 8, r->name);
if (flags & EXTRACT_ENTROPY_LIMIT && nbytes >= r->entropy_count / 8)
nbytes = r->entropy_count / 8;
@@ -1388,12 +1385,8 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
if (r->entropy_count < random_write_wakeup_thresh)
wake_up_interruptible(&random_write_wait);
- DEBUG_ENT("%04d %04d : debiting %d bits from %s%s\n",
- random_state->entropy_count,
- sec_random_state->entropy_count,
- nbytes * 8,
- r == sec_random_state ? "secondary" :
- r == random_state ? "primary" : "unknown",
+ DEBUG_ENT("Debiting %d entropy credits from %s%s\n",
+ nbytes * 8, r->name,
flags & EXTRACT_ENTROPY_LIMIT ? "" : " (unlimited)");
spin_unlock_irqrestore(&r->lock, cpuflags);
@@ -1482,14 +1475,21 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
*/
void get_random_bytes(void *buf, int nbytes)
{
- if (sec_random_state)
- extract_entropy(sec_random_state, (char *) buf, nbytes,
- EXTRACT_ENTROPY_SECONDARY);
- else if (random_state)
- extract_entropy(random_state, (char *) buf, nbytes, 0);
- else
+ struct entropy_store *r = urandom_state;
+ int flags = EXTRACT_ENTROPY_SECONDARY;
+
+ if (!r)
+ r = sec_random_state;
+ if (!r) {
+ r = random_state;
+ flags = 0;
+ }
+ if (!r) {
printk(KERN_NOTICE "get_random_bytes called before "
"random driver initialization\n");
+ return;
+ }
+ extract_entropy(r, (char *) buf, nbytes, flags);
}
EXPORT_SYMBOL(get_random_bytes);
@@ -1533,14 +1533,19 @@ static int __init rand_initialize(void)
{
int i;
- if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state))
+ if (create_entropy_store(DEFAULT_POOL_SIZE, "primary", &random_state))
goto err;
if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state))
goto err;
- if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state))
+ if (create_entropy_store(SECONDARY_POOL_SIZE, "secondary",
+ &sec_random_state))
+ goto err;
+ if (create_entropy_store(SECONDARY_POOL_SIZE, "urandom",
+ &urandom_state))
goto err;
clear_entropy_store(random_state);
clear_entropy_store(sec_random_state);
+ clear_entropy_store(urandom_state);
init_std_data(random_state);
init_std_data(sec_random_state);
#ifdef CONFIG_SYSCTL
@@ -1675,9 +1680,15 @@ static ssize_t
urandom_read(struct file * file, char __user * buf,
size_t nbytes, loff_t *ppos)
{
- return extract_entropy(sec_random_state, buf, nbytes,
- EXTRACT_ENTROPY_USER |
- EXTRACT_ENTROPY_SECONDARY);
+ int flags = EXTRACT_ENTROPY_USER;
+ unsigned long cpuflags;
+
+ spin_lock_irqsave(&random_state->lock, cpuflags);
+ if (random_state->entropy_count > random_state->poolinfo.POOLBITS)
+ flags |= EXTRACT_ENTROPY_SECONDARY;
+ spin_unlock_irqrestore(&random_state->lock, cpuflags);
+
+ return extract_entropy(urandom_state, buf, nbytes, flags);
}
static unsigned int
@@ -1731,10 +1742,9 @@ static int
random_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int *tmp, size, ent_count;
+ int size, ent_count;
int __user *p = (int __user *)arg;
int retval;
- unsigned long flags;
switch (cmd) {
case RNDGETENTCNT:
@@ -1755,40 +1765,6 @@ random_ioctl(struct inode * inode, struct file * file,
if (random_state->entropy_count >= random_read_wakeup_thresh)
wake_up_interruptible(&random_read_wait);
return 0;
- case RNDGETPOOL:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (get_user(size, p) ||
- put_user(random_state->poolinfo.poolwords, p++))
- return -EFAULT;
- if (size < 0)
- return -EFAULT;
- if (size > random_state->poolinfo.poolwords)
- size = random_state->poolinfo.poolwords;
-
- /* prepare to atomically snapshot pool */
-
- tmp = kmalloc(size * sizeof(__u32), GFP_KERNEL);
-
- if (!tmp)
- return -ENOMEM;
-
- spin_lock_irqsave(&random_state->lock, flags);
- ent_count = random_state->entropy_count;
- memcpy(tmp, random_state->pool, size * sizeof(__u32));
- spin_unlock_irqrestore(&random_state->lock, flags);
-
- if (!copy_to_user(p, tmp, size * sizeof(__u32))) {
- kfree(tmp);
- return -EFAULT;
- }
-
- kfree(tmp);
-
- if(put_user(ent_count, p++))
- return -EFAULT;
-
- return 0;
case RNDADDENTROPY:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1885,7 +1861,8 @@ static int change_poolsize(int poolsize)
struct entropy_store *new_store, *old_store;
int ret;
- if ((ret = create_entropy_store(poolsize, &new_store)))
+ if ((ret = create_entropy_store(poolsize, random_state->name,
+ &new_store)))
return ret;
add_entropy_words(new_store, random_state->pool,
@@ -2247,30 +2224,35 @@ static struct keydata {
static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED;
static unsigned int ip_cnt;
-static struct keydata *__check_and_rekey(time_t time)
+static void rekey_seq_generator(void *private_)
{
struct keydata *keyptr;
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+
spin_lock_bh(&ip_lock);
keyptr = &ip_keydata[ip_cnt&1];
- if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
- keyptr = &ip_keydata[1^(ip_cnt&1)];
- keyptr->rekey_time = time;
- get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
- keyptr->count = (ip_cnt&COUNT_MASK)<<HASH_BITS;
- mb();
- ip_cnt++;
- }
+
+ keyptr = &ip_keydata[1^(ip_cnt&1)];
+ keyptr->rekey_time = tv.tv_sec;
+ get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
+ keyptr->count = (ip_cnt&COUNT_MASK)<<HASH_BITS;
+ mb();
+ ip_cnt++;
+
spin_unlock_bh(&ip_lock);
- return keyptr;
}
+static DECLARE_WORK(rekey_work, rekey_seq_generator, NULL);
+
static inline struct keydata *check_and_rekey(time_t time)
{
struct keydata *keyptr = &ip_keydata[ip_cnt&1];
rmb();
if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
- keyptr = __check_and_rekey(time);
+ schedule_work(&rekey_work);
}
return keyptr;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 129b8ccd85b7e..a2efa67afdcb3 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1283,11 +1283,7 @@ static int set_config(struct r_port *info, struct rocket_config __user *new_info
if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
return -EFAULT;
-#ifdef CAP_SYS_ADMIN
if (!capable(CAP_SYS_ADMIN))
-#else
- if (!suser())
-#endif
{
if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
return -EPERM;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 1b51eecfb931e..fd902442fc739 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2379,7 +2379,7 @@ scrn[1] = '\0';
| CyPARITY| CyFRAME| CyOVERRUN;
/* info->timeout */
- printk("ttyS%1d ", info->line);
+ printk("ttyS%d ", info->line);
port_num++;info++;
if(!(port_num & 7)){
printk("\n ");
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 0a517eb28b933..aa7c91d6f171c 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -67,7 +67,7 @@ static unsigned long mask = 0xffffffff;
static inline void sonypi_initq(void) {
sonypi_device.queue.head = sonypi_device.queue.tail = 0;
sonypi_device.queue.len = 0;
- sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+ sonypi_device.queue.s_lock = SPIN_LOCK_UNLOCKED;
init_waitqueue_head(&sonypi_device.queue.proc_list);
}
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 78d4efe6f80e7..3665d0f5713e8 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/synclink.c
*
- * $Id: synclink.c,v 4.24 2004/06/03 14:50:09 paulkf Exp $
+ * $Id: synclink.c,v 4.28 2004/08/11 19:30:01 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
@@ -100,13 +100,10 @@
#include <asm/types.h>
#include <linux/termios.h>
#include <linux/workqueue.h>
+#include <linux/hdlc.h>
-#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
-#define CONFIG_SYNCLINK_SYNCPPP 1
-#endif
-
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-#include <net/syncppp.h>
+#ifdef CONFIG_HDLC_MODULE
+#define CONFIG_HDLC 1
#endif
#define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -187,7 +184,6 @@ struct tx_holding_buffer {
*/
struct mgsl_struct {
- void *if_ptr; /* General purpose pointer (used by SPPP) */
int magic;
int flags;
int count; /* count of opens */
@@ -318,15 +314,13 @@ struct mgsl_struct {
struct _input_signal_events input_signal_events;
- /* SPPP/Cisco HDLC device parts */
+ /* generic HDLC device parts */
int netcount;
int dosyncppp;
spinlock_t netlock;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- struct ppp_device pppdev;
- char netname[10];
+
+#ifdef CONFIG_HDLC
struct net_device *netdev;
- struct net_device_stats netstats;
#endif
};
@@ -734,18 +728,12 @@ int usc_loopmode_send_active( struct mgsl_struct * info );
int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-/* SPPP/HDLC stuff */
-static void mgsl_sppp_init(struct mgsl_struct *info);
-static void mgsl_sppp_delete(struct mgsl_struct *info);
-int mgsl_sppp_open(struct net_device *d);
-int mgsl_sppp_close(struct net_device *d);
-void mgsl_sppp_tx_timeout(struct net_device *d);
-int mgsl_sppp_tx(struct sk_buff *skb, struct net_device *d);
-void mgsl_sppp_rx_done(struct mgsl_struct *info, char *buf, int size);
-void mgsl_sppp_tx_done(struct mgsl_struct *info);
-int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-struct net_device_stats *mgsl_net_stats(struct net_device *dev);
+#ifdef CONFIG_HDLC
+#define dev_to_port(D) (dev_to_hdlc(D)->priv)
+static void hdlcdev_tx_done(struct mgsl_struct *info);
+static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size);
+static int hdlcdev_init(struct mgsl_struct *info);
+static void hdlcdev_exit(struct mgsl_struct *info);
#endif
/*
@@ -911,7 +899,7 @@ MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.24 $";
+static char *driver_version = "$Revision: 4.28 $";
static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
@@ -1289,9 +1277,9 @@ void mgsl_isr_transmit_status( struct mgsl_struct *info )
info->drop_rts_on_tx_done = 0;
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef CONFIG_HDLC
if (info->netcount)
- mgsl_sppp_tx_done(info);
+ hdlcdev_tx_done(info);
else
#endif
{
@@ -1352,12 +1340,12 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
icount->dcd++;
if (status & MISCSTATUS_DCD) {
info->input_signal_events.dcd_up++;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount)
- sppp_reopen(info->netdev);
-#endif
} else
info->input_signal_events.dcd_down++;
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlc_set_carrier(status & MISCSTATUS_DCD, info->netdev);
+#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
{
@@ -3592,7 +3580,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
cleanup:
if (retval) {
if (tty->count == 1)
- info->tty = NULL;/* tty layer will release tty struct */
+ info->tty = NULL; /* tty layer will release tty struct */
if(info->count)
info->count--;
}
@@ -4415,12 +4403,10 @@ void mgsl_add_device( struct mgsl_struct *info )
info->max_frame_size );
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-#ifdef MODULE
- if (info->dosyncppp)
-#endif
- mgsl_sppp_init(info);
+#ifdef CONFIG_HDLC
+ hdlcdev_init(info);
#endif
+
} /* end of mgsl_add_device() */
/* mgsl_allocate_device()
@@ -4575,9 +4561,8 @@ static void synclink_cleanup(void)
info = mgsl_device_list;
while(info) {
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->dosyncppp)
- mgsl_sppp_delete(info);
+#ifdef CONFIG_HDLC
+ hdlcdev_exit(info);
#endif
mgsl_release_resources(info);
tmp = info;
@@ -6750,9 +6735,12 @@ int mgsl_get_rx_frame(struct mgsl_struct *info)
return_frame = 1;
}
framesize = 0;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- info->netstats.rx_errors++;
- info->netstats.rx_frame_errors++;
+#ifdef CONFIG_HDLC
+ {
+ struct net_device_stats *stats = hdlc_stats(info->netdev);
+ stats->rx_errors++;
+ stats->rx_frame_errors++;
+ }
#endif
} else
return_frame = 1;
@@ -6823,11 +6811,9 @@ int mgsl_get_rx_frame(struct mgsl_struct *info)
*ptmp);
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount) {
- /* pass frame to syncppp device */
- mgsl_sppp_rx_done(info,info->intermediate_rxbuffer,framesize);
- }
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlcdev_rx(info,info->intermediate_rxbuffer,framesize);
else
#endif
{
@@ -7736,9 +7722,9 @@ void mgsl_tx_timeout(unsigned long context)
spin_unlock_irqrestore(&info->irq_spinlock,flags);
-#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef CONFIG_HDLC
if (info->netcount)
- mgsl_sppp_tx_done(info);
+ hdlcdev_tx_done(info);
else
#endif
mgsl_bh_transmit(info);
@@ -7819,79 +7805,125 @@ int usc_loopmode_send_active( struct mgsl_struct * info )
return usc_InReg( info, CCSR ) & BIT6 ? 1 : 0 ;
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-/* syncppp net device routines
- */
-static void mgsl_setup(struct net_device *dev)
-{
- dev->open = mgsl_sppp_open;
- dev->stop = mgsl_sppp_close;
- dev->hard_start_xmit = mgsl_sppp_tx;
- dev->do_ioctl = mgsl_sppp_ioctl;
- dev->get_stats = mgsl_net_stats;
- dev->tx_timeout = mgsl_sppp_tx_timeout;
- dev->watchdog_timeo = 10*HZ;
-}
+#ifdef CONFIG_HDLC
-static void mgsl_sppp_init(struct mgsl_struct *info)
+/**
+ * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
+ * set encoding and frame check sequence (FCS) options
+ *
+ * dev pointer to network device structure
+ * encoding serial encoding setting
+ * parity FCS setting
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
+ unsigned short parity)
{
- struct net_device *d;
+ struct mgsl_struct *info = dev_to_port(dev);
+ unsigned char new_encoding;
+ unsigned short new_crctype;
- sprintf(info->netname,"mgsl%d",info->line);
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
- d = alloc_netdev(0, info->netname, mgsl_setup);
- if (!d) {
- printk(KERN_WARNING "%s: alloc_netdev failed.\n",
- info->netname);
- return;
+ switch (encoding)
+ {
+ case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break;
+ case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
+ case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
+ case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
+ case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
+ default: return -EINVAL;
}
- info->if_ptr = &info->pppdev;
- info->netdev = info->pppdev.dev = d;
-
- d->base_addr = info->io_base;
- d->irq = info->irq_level;
- d->dma = info->dma_level;
- d->priv = info;
+ switch (parity)
+ {
+ case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break;
+ case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
+ case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
+ default: return -EINVAL;
+ }
- sppp_attach(&info->pppdev);
- mgsl_setup(d);
+ info->params.encoding = new_encoding;
+ info->params.crc_type = new_crctype;;
- if (register_netdev(d)) {
- printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
- sppp_detach(info->netdev);
- info->netdev = NULL;
- free_netdev(d);
- return;
- }
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ mgsl_program_hw(info);
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_init()\n");
+ return 0;
}
-void mgsl_sppp_delete(struct mgsl_struct *info)
+/**
+ * called by generic HDLC layer to send frame
+ *
+ * skb socket buffer containing HDLC frame
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ struct mgsl_struct *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
+ unsigned long flags;
+
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_delete(%s)\n",info->netname);
- unregister_netdev(info->netdev);
- sppp_detach(info->netdev);
- free_netdev(info->netdev);
- info->netdev = NULL;
- info->pppdev.dev = NULL;
+ printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name);
+
+ /* stop sending until this frame completes */
+ netif_stop_queue(dev);
+
+ /* copy data to device buffers */
+ info->xmit_cnt = skb->len;
+ mgsl_load_tx_dma_buffer(info, skb->data, skb->len);
+
+ /* update network statistics */
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+
+ /* done with socket buffer, so free it */
+ dev_kfree_skb(skb);
+
+ /* save start time for transmit timeout detection */
+ dev->trans_start = jiffies;
+
+ /* start hardware transmitter if necessary */
+ spin_lock_irqsave(&info->irq_spinlock,flags);
+ if (!info->tx_active)
+ usc_start_transmitter(info);
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+ return 0;
}
-int mgsl_sppp_open(struct net_device *d)
+/**
+ * called by network layer when interface enabled
+ * claim resources and initialize hardware
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_open(struct net_device *dev)
{
- struct mgsl_struct *info = d->priv;
- int err;
+ struct mgsl_struct *info = dev_to_port(dev);
+ int rc;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_open(%s)\n",info->netname);
+ printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
+
+ /* generic HDLC layer open processing */
+ if ((rc = hdlc_open(dev)))
+ return rc;
+ /* arbitrate between network and tty opens */
spin_lock_irqsave(&info->netlock, flags);
if (info->count != 0 || info->netcount != 0) {
- printk(KERN_WARNING "%s: sppp_open returning busy\n", info->netname);
+ printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
spin_unlock_irqrestore(&info->netlock, flags);
return -EBUSY;
}
@@ -7899,141 +7931,301 @@ int mgsl_sppp_open(struct net_device *d)
spin_unlock_irqrestore(&info->netlock, flags);
/* claim resources and init adapter */
- if ((err = startup(info)) != 0)
- goto open_fail;
-
- /* allow syncppp module to do open processing */
- if ((err = sppp_open(d)) != 0) {
- shutdown(info);
- goto open_fail;
+ if ((rc = startup(info)) != 0) {
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+ return rc;
}
+ /* assert DTR and RTS, apply hardware settings */
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
mgsl_program_hw(info);
- d->trans_start = jiffies;
- netif_start_queue(d);
- return 0;
+ /* enable network layer transmit */
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
-open_fail:
- spin_lock_irqsave(&info->netlock, flags);
- info->netcount=0;
- spin_unlock_irqrestore(&info->netlock, flags);
- return err;
+ /* inform generic HDLC layer of current DCD status */
+ spin_lock_irqsave(&info->irq_spinlock, flags);
+ usc_get_serial_signals(info);
+ spin_unlock_irqrestore(&info->irq_spinlock, flags);
+ hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
+
+ return 0;
}
-void mgsl_sppp_tx_timeout(struct net_device *dev)
+/**
+ * called by network layer when interface is disabled
+ * shutdown hardware and release resources
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_close(struct net_device *dev)
{
- struct mgsl_struct *info = dev->priv;
+ struct mgsl_struct *info = dev_to_port(dev);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_tx_timeout(%s)\n",info->netname);
+ printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name);
- info->netstats.tx_errors++;
- info->netstats.tx_aborted_errors++;
+ netif_stop_queue(dev);
- spin_lock_irqsave(&info->irq_spinlock,flags);
- usc_stop_transmitter(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ /* shutdown adapter and release resources */
+ shutdown(info);
- netif_wake_queue(dev);
+ hdlc_close(dev);
+
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+
+ return 0;
}
-int mgsl_sppp_tx(struct sk_buff *skb, struct net_device *dev)
+/**
+ * called by network layer to process IOCTL call to network device
+ *
+ * dev pointer to network device structure
+ * ifr pointer to network interface request structure
+ * cmd IOCTL command code
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct mgsl_struct *info = dev->priv;
- unsigned long flags;
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ struct mgsl_struct *info = dev_to_port(dev);
+ unsigned int flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_tx(%s)\n",info->netname);
+ printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
- netif_stop_queue(dev);
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
- info->xmit_cnt = skb->len;
- mgsl_load_tx_dma_buffer(info, skb->data, skb->len);
- info->netstats.tx_packets++;
- info->netstats.tx_bytes += skb->len;
- dev_kfree_skb(skb);
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
- dev->trans_start = jiffies;
+ switch(ifr->ifr_settings.type) {
+ case IF_GET_IFACE: /* return current sync_serial_settings */
- spin_lock_irqsave(&info->irq_spinlock,flags);
- if (!info->tx_active)
- usc_start_transmitter(info);
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
- return 0;
+ flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+
+ switch (flags){
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
+ case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
+ default: new_line.clock_type = CLOCK_DEFAULT;
+ }
+
+ new_line.clock_rate = info->params.clock_speed;
+ new_line.loopback = info->params.loopback ? 1:0;
+
+ if (copy_to_user(line, &new_line, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ switch (new_line.clock_type)
+ {
+ case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
+ case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
+ case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_DEFAULT: flags = info->params.flags &
+ (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break;
+ default: return -EINVAL;
+ }
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+ info->params.flags |= flags;
+
+ info->params.loopback = new_line.loopback;
+
+ if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
+ info->params.clock_speed = new_line.clock_rate;
+ else
+ info->params.clock_speed = 0;
+
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ mgsl_program_hw(info);
+ return 0;
+
+ default:
+ return hdlc_ioctl(dev, ifr, cmd);
+ }
}
-int mgsl_sppp_close(struct net_device *d)
+/**
+ * called by network layer when transmit timeout is detected
+ *
+ * dev pointer to network device structure
+ */
+static void hdlcdev_tx_timeout(struct net_device *dev)
{
- struct mgsl_struct *info = d->priv;
+ struct mgsl_struct *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_close(%s)\n",info->netname);
+ printk("hdlcdev_tx_timeout(%s)\n",dev->name);
- /* shutdown adapter and release resources */
- shutdown(info);
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
- /* allow syncppp to do close processing */
- sppp_close(d);
- netif_stop_queue(d);
+ spin_lock_irqsave(&info->irq_spinlock,flags);
+ usc_stop_transmitter(info);
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
- spin_lock_irqsave(&info->netlock, flags);
- info->netcount=0;
- spin_unlock_irqrestore(&info->netlock, flags);
- return 0;
+ netif_wake_queue(dev);
}
-void mgsl_sppp_rx_done(struct mgsl_struct *info, char *buf, int size)
+/**
+ * called by device driver when transmit completes
+ * reenable network layer transmit if stopped
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_tx_done(struct mgsl_struct *info)
+{
+ if (netif_queue_stopped(info->netdev))
+ netif_wake_queue(info->netdev);
+}
+
+/**
+ * called by device driver when frame received
+ * pass frame to network layer
+ *
+ * info pointer to device instance information
+ * buf pointer to buffer contianing frame data
+ * size count of data bytes in buf
+ */
+static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size)
{
struct sk_buff *skb = dev_alloc_skb(size);
+ struct net_device *dev = info->netdev;
+ struct net_device_stats *stats = hdlc_stats(dev);
+
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_sppp_rx_done(%s)\n",info->netname);
+ printk("hdlcdev_rx(%s)\n",dev->name);
+
if (skb == NULL) {
- printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n",
- info->netname);
- info->netstats.rx_dropped++;
+ printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name);
+ stats->rx_dropped++;
return;
}
memcpy(skb_put(skb, size),buf,size);
- skb->protocol = htons(ETH_P_WAN_PPP);
- skb->dev = info->netdev;
- skb->mac.raw = skb->data;
- info->netstats.rx_packets++;
- info->netstats.rx_bytes += size;
+ skb->dev = info->netdev;
+ skb->mac.raw = skb->data;
+ skb->protocol = hdlc_type_trans(skb, skb->dev);
+
+ stats->rx_packets++;
+ stats->rx_bytes += size;
+
netif_rx(skb);
- info->netdev->trans_start = jiffies;
-}
-void mgsl_sppp_tx_done(struct mgsl_struct *info)
-{
- if (netif_queue_stopped(info->netdev))
- netif_wake_queue(info->netdev);
+ info->netdev->last_rx = jiffies;
}
-struct net_device_stats *mgsl_net_stats(struct net_device *dev)
+/**
+ * called by device driver when adding device instance
+ * do generic HDLC initialization
+ *
+ * info pointer to device instance information
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_init(struct mgsl_struct *info)
{
- struct mgsl_struct *info = dev->priv;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("mgsl_net_stats(%s)\n",info->netname);
- return &info->netstats;
+ int rc;
+ struct net_device *dev;
+ hdlc_device *hdlc;
+
+ /* allocate and initialize network and HDLC layer objects */
+
+ if (!(dev = alloc_hdlcdev(info))) {
+ printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
+ return -ENOMEM;
+ }
+
+ /* for network layer reporting purposes only */
+ dev->base_addr = info->io_base;
+ dev->irq = info->irq_level;
+ dev->dma = info->dma_level;
+
+ /* network layer callbacks and settings */
+ dev->do_ioctl = hdlcdev_ioctl;
+ dev->open = hdlcdev_open;
+ dev->stop = hdlcdev_close;
+ dev->tx_timeout = hdlcdev_tx_timeout;
+ dev->watchdog_timeo = 10*HZ;
+ dev->tx_queue_len = 50;
+
+ /* generic HDLC layer callbacks and settings */
+ hdlc = dev_to_hdlc(dev);
+ hdlc->attach = hdlcdev_attach;
+ hdlc->xmit = hdlcdev_xmit;
+
+ /* register objects with HDLC layer */
+ if ((rc = register_hdlc_device(dev))) {
+ printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
+ free_netdev(dev);
+ return rc;
+ }
+
+ info->netdev = dev;
+ return 0;
}
-int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/**
+ * called by device driver when removing device instance
+ * do generic HDLC cleanup
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_exit(struct mgsl_struct *info)
{
- struct mgsl_struct *info = dev->priv;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
- info->netname, cmd );
- return sppp_do_ioctl(dev, ifr, cmd);
+ unregister_hdlc_device(info->netdev);
+ free_netdev(info->netdev);
+ info->netdev = NULL;
}
-#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
+#endif /* CONFIG_HDLC */
+
static int __devinit synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent)
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 1361ea04151c3..9eb1a62559349 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1,5 +1,5 @@
/*
- * $Id: synclinkmp.c,v 4.22 2004/06/03 14:50:10 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $
*
* Device driver for Microgate SyncLink Multiport
* high speed multiprotocol serial adapter.
@@ -67,13 +67,10 @@
#include <asm/types.h>
#include <linux/termios.h>
#include <linux/workqueue.h>
+#include <linux/hdlc.h>
-#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
-#define CONFIG_SYNCLINK_SYNCPPP 1
-#endif
-
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-#include <net/syncppp.h>
+#ifdef CONFIG_HDLC_MODULE
+#define CONFIG_HDLC 1
#endif
#define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -284,12 +281,11 @@ typedef struct _synclinkmp_info {
int netcount;
int dosyncppp;
spinlock_t netlock;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- struct ppp_device pppdev;
- char netname[10];
+
+#ifdef CONFIG_HDLC
struct net_device *netdev;
- struct net_device_stats netstats;
#endif
+
} SLMP_INFO;
#define MGSL_MAGIC 0x5401
@@ -361,12 +357,7 @@ typedef struct _synclinkmp_info {
#define TMCS 0x64
#define TEPR 0x65
-/*
- * FIXME: DAR here clashed with asm-ppc/reg.h and asm-sh/.../dma.h
- */
-#undef DAR
/* DMA Controller Register macros */
-#define DAR 0x80
#define DARL 0x80
#define DARH 0x81
#define DARB 0x82
@@ -498,7 +489,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.22 $";
+static char *driver_version = "$Revision: 4.26 $";
static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -553,20 +544,12 @@ static void throttle(struct tty_struct * tty);
static void unthrottle(struct tty_struct * tty);
static void set_break(struct tty_struct *tty, int break_state);
-/* sppp support and callbacks */
-
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-static void sppp_init(SLMP_INFO *info);
-static void sppp_delete(SLMP_INFO *info);
-static void sppp_rx_done(SLMP_INFO *info, char *buf, int size);
-static void sppp_tx_done(SLMP_INFO *info);
-
-static int sppp_cb_open(struct net_device *d);
-static int sppp_cb_close(struct net_device *d);
-static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev);
-static void sppp_cb_tx_timeout(struct net_device *dev);
-static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev);
+#ifdef CONFIG_HDLC
+#define dev_to_port(D) (dev_to_hdlc(D)->priv)
+static void hdlcdev_tx_done(SLMP_INFO *info);
+static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size);
+static int hdlcdev_init(SLMP_INFO *info);
+static void hdlcdev_exit(SLMP_INFO *info);
#endif
/* ioctl handlers */
@@ -800,7 +783,7 @@ static int open(struct tty_struct *tty, struct file *filp)
cleanup:
if (retval) {
if (tty->count == 1)
- info->tty = NULL;/* tty layer will release tty struct */
+ info->tty = NULL; /* tty layer will release tty struct */
if(info->count)
info->count--;
}
@@ -1627,79 +1610,125 @@ static void set_break(struct tty_struct *tty, int break_state)
spin_unlock_irqrestore(&info->lock,flags);
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
-
-/* syncppp support and callbacks */
+#ifdef CONFIG_HDLC
-static void cb_setup(struct net_device *dev)
-{
- dev->open = sppp_cb_open;
- dev->stop = sppp_cb_close;
- dev->hard_start_xmit = sppp_cb_tx;
- dev->do_ioctl = sppp_cb_ioctl;
- dev->get_stats = sppp_cb_net_stats;
- dev->tx_timeout = sppp_cb_tx_timeout;
- dev->watchdog_timeo = 10*HZ;
-}
-
-static void sppp_init(SLMP_INFO *info)
+/**
+ * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
+ * set encoding and frame check sequence (FCS) options
+ *
+ * dev pointer to network device structure
+ * encoding serial encoding setting
+ * parity FCS setting
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
+ unsigned short parity)
{
- struct net_device *d;
+ SLMP_INFO *info = dev_to_port(dev);
+ unsigned char new_encoding;
+ unsigned short new_crctype;
- sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num);
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
- d = alloc_netdev(0, info->netname, cb_setup);
- if (!d) {
- printk(KERN_WARNING "%s: alloc_netdev failed.\n",
- info->netname);
- return;
+ switch (encoding)
+ {
+ case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break;
+ case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
+ case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
+ case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
+ case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
+ default: return -EINVAL;
}
- info->if_ptr = &info->pppdev;
- info->netdev = info->pppdev.dev = d;
-
- d->irq = info->irq_level;
- d->priv = info;
+ switch (parity)
+ {
+ case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break;
+ case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
+ case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
+ default: return -EINVAL;
+ }
- sppp_attach(&info->pppdev);
- cb_setup(d);
+ info->params.encoding = new_encoding;
+ info->params.crc_type = new_crctype;;
- if (register_netdev(d)) {
- printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
- sppp_detach(info->netdev);
- info->netdev = NULL;
- info->pppdev.dev = NULL;
- free_netdev(d);
- return;
- }
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ program_hw(info);
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_init(%s)\n",info->netname);
+ return 0;
}
-static void sppp_delete(SLMP_INFO *info)
+/**
+ * called by generic HDLC layer to send frame
+ *
+ * skb socket buffer containing HDLC frame
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ SLMP_INFO *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
+ unsigned long flags;
+
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_delete(%s)\n",info->netname);
- unregister_netdev(info->netdev);
- sppp_detach(info->netdev);
- free_netdev(info->netdev);
- info->netdev = NULL;
- info->pppdev.dev = NULL;
+ printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name);
+
+ /* stop sending until this frame completes */
+ netif_stop_queue(dev);
+
+ /* copy data to device buffers */
+ info->tx_count = skb->len;
+ tx_load_dma_buffer(info, skb->data, skb->len);
+
+ /* update network statistics */
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+
+ /* done with socket buffer, so free it */
+ dev_kfree_skb(skb);
+
+ /* save start time for transmit timeout detection */
+ dev->trans_start = jiffies;
+
+ /* start hardware transmitter if necessary */
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active)
+ tx_start(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ return 0;
}
-static int sppp_cb_open(struct net_device *d)
+/**
+ * called by network layer when interface enabled
+ * claim resources and initialize hardware
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_open(struct net_device *dev)
{
- SLMP_INFO *info = d->priv;
- int err;
+ SLMP_INFO *info = dev_to_port(dev);
+ int rc;
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_cb_open(%s)\n",info->netname);
+ printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
+ /* generic HDLC layer open processing */
+ if ((rc = hdlc_open(dev)))
+ return rc;
+
+ /* arbitrate between network and tty opens */
spin_lock_irqsave(&info->netlock, flags);
if (info->count != 0 || info->netcount != 0) {
- printk(KERN_WARNING "%s: sppp_cb_open returning busy\n", info->netname);
+ printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name);
spin_unlock_irqrestore(&info->netlock, flags);
return -EBUSY;
}
@@ -1707,141 +1736,300 @@ static int sppp_cb_open(struct net_device *d)
spin_unlock_irqrestore(&info->netlock, flags);
/* claim resources and init adapter */
- if ((err = startup(info)) != 0)
- goto open_fail;
-
- /* allow syncppp module to do open processing */
- if ((err = sppp_open(d)) != 0) {
- shutdown(info);
- goto open_fail;
+ if ((rc = startup(info)) != 0) {
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+ return rc;
}
+ /* assert DTR and RTS, apply hardware settings */
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
program_hw(info);
- d->trans_start = jiffies;
- netif_start_queue(d);
- return 0;
+ /* enable network layer transmit */
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
-open_fail:
- spin_lock_irqsave(&info->netlock, flags);
- info->netcount=0;
- spin_unlock_irqrestore(&info->netlock, flags);
- return err;
+ /* inform generic HDLC layer of current DCD status */
+ spin_lock_irqsave(&info->lock, flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
+ hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
+
+ return 0;
}
-static void sppp_cb_tx_timeout(struct net_device *dev)
+/**
+ * called by network layer when interface is disabled
+ * shutdown hardware and release resources
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_close(struct net_device *dev)
{
- SLMP_INFO *info = dev->priv;
+ SLMP_INFO *info = dev_to_port(dev);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_tx_timeout(%s)\n",info->netname);
+ printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name);
- info->netstats.tx_errors++;
- info->netstats.tx_aborted_errors++;
+ netif_stop_queue(dev);
- spin_lock_irqsave(&info->lock,flags);
- tx_stop(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ /* shutdown adapter and release resources */
+ shutdown(info);
- netif_wake_queue(dev);
+ hdlc_close(dev);
+
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+
+ return 0;
}
-static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev)
+/**
+ * called by network layer to process IOCTL call to network device
+ *
+ * dev pointer to network device structure
+ * ifr pointer to network interface request structure
+ * cmd IOCTL command code
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- SLMP_INFO *info = dev->priv;
- unsigned long flags;
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ SLMP_INFO *info = dev_to_port(dev);
+ unsigned int flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_tx(%s)\n",info->netname);
+ printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name);
- netif_stop_queue(dev);
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
- info->tx_count = skb->len;
- tx_load_dma_buffer(info, skb->data, skb->len);
- info->netstats.tx_packets++;
- info->netstats.tx_bytes += skb->len;
- dev_kfree_skb(skb);
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
- dev->trans_start = jiffies;
+ switch(ifr->ifr_settings.type) {
+ case IF_GET_IFACE: /* return current sync_serial_settings */
- spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active)
- tx_start(info);
- spin_unlock_irqrestore(&info->lock,flags);
+ ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
- return 0;
+ flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+
+ switch (flags){
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
+ case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
+ default: new_line.clock_type = CLOCK_DEFAULT;
+ }
+
+ new_line.clock_rate = info->params.clock_speed;
+ new_line.loopback = info->params.loopback ? 1:0;
+
+ if (copy_to_user(line, &new_line, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ switch (new_line.clock_type)
+ {
+ case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
+ case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
+ case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_DEFAULT: flags = info->params.flags &
+ (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break;
+ default: return -EINVAL;
+ }
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+ info->params.flags |= flags;
+
+ info->params.loopback = new_line.loopback;
+
+ if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
+ info->params.clock_speed = new_line.clock_rate;
+ else
+ info->params.clock_speed = 0;
+
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ program_hw(info);
+ return 0;
+
+ default:
+ return hdlc_ioctl(dev, ifr, cmd);
+ }
}
-static int sppp_cb_close(struct net_device *d)
+/**
+ * called by network layer when transmit timeout is detected
+ *
+ * dev pointer to network device structure
+ */
+static void hdlcdev_tx_timeout(struct net_device *dev)
{
- SLMP_INFO *info = d->priv;
+ SLMP_INFO *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
unsigned long flags;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_cb_close(%s)\n",info->netname);
+ printk("hdlcdev_tx_timeout(%s)\n",dev->name);
- /* shutdown adapter and release resources */
- shutdown(info);
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
- /* allow syncppp to do close processing */
- sppp_close(d);
- netif_stop_queue(d);
+ spin_lock_irqsave(&info->lock,flags);
+ tx_stop(info);
+ spin_unlock_irqrestore(&info->lock,flags);
- spin_lock_irqsave(&info->netlock, flags);
- info->netcount=0;
- spin_unlock_irqrestore(&info->netlock, flags);
- return 0;
+ netif_wake_queue(dev);
+}
+
+/**
+ * called by device driver when transmit completes
+ * reenable network layer transmit if stopped
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_tx_done(SLMP_INFO *info)
+{
+ if (netif_queue_stopped(info->netdev))
+ netif_wake_queue(info->netdev);
}
-static void sppp_rx_done(SLMP_INFO *info, char *buf, int size)
+/**
+ * called by device driver when frame received
+ * pass frame to network layer
+ *
+ * info pointer to device instance information
+ * buf pointer to buffer contianing frame data
+ * size count of data bytes in buf
+ */
+static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size)
{
struct sk_buff *skb = dev_alloc_skb(size);
+ struct net_device *dev = info->netdev;
+ struct net_device_stats *stats = hdlc_stats(dev);
+
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("sppp_rx_done(%s)\n",info->netname);
+ printk("hdlcdev_rx(%s)\n",dev->name);
+
if (skb == NULL) {
- printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n",
- info->netname);
- info->netstats.rx_dropped++;
+ printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name);
+ stats->rx_dropped++;
return;
}
memcpy(skb_put(skb, size),buf,size);
- skb->protocol = htons(ETH_P_WAN_PPP);
- skb->dev = info->netdev;
- skb->mac.raw = skb->data;
- info->netstats.rx_packets++;
- info->netstats.rx_bytes += size;
+ skb->dev = info->netdev;
+ skb->mac.raw = skb->data;
+ skb->protocol = hdlc_type_trans(skb, skb->dev);
+
+ stats->rx_packets++;
+ stats->rx_bytes += size;
+
netif_rx(skb);
- info->netdev->trans_start = jiffies;
-}
-static void sppp_tx_done(SLMP_INFO *info)
-{
- if (netif_queue_stopped(info->netdev))
- netif_wake_queue(info->netdev);
+ info->netdev->last_rx = jiffies;
}
-static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev)
+/**
+ * called by device driver when adding device instance
+ * do generic HDLC initialization
+ *
+ * info pointer to device instance information
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_init(SLMP_INFO *info)
{
- SLMP_INFO *info = dev->priv;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("net_stats(%s)\n",info->netname);
- return &info->netstats;
+ int rc;
+ struct net_device *dev;
+ hdlc_device *hdlc;
+
+ /* allocate and initialize network and HDLC layer objects */
+
+ if (!(dev = alloc_hdlcdev(info))) {
+ printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
+ return -ENOMEM;
+ }
+
+ /* for network layer reporting purposes only */
+ dev->mem_start = info->phys_sca_base;
+ dev->mem_end = info->phys_sca_base + SCA_BASE_SIZE - 1;
+ dev->irq = info->irq_level;
+
+ /* network layer callbacks and settings */
+ dev->do_ioctl = hdlcdev_ioctl;
+ dev->open = hdlcdev_open;
+ dev->stop = hdlcdev_close;
+ dev->tx_timeout = hdlcdev_tx_timeout;
+ dev->watchdog_timeo = 10*HZ;
+ dev->tx_queue_len = 50;
+
+ /* generic HDLC layer callbacks and settings */
+ hdlc = dev_to_hdlc(dev);
+ hdlc->attach = hdlcdev_attach;
+ hdlc->xmit = hdlcdev_xmit;
+
+ /* register objects with HDLC layer */
+ if ((rc = register_hdlc_device(dev))) {
+ printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
+ free_netdev(dev);
+ return rc;
+ }
+
+ info->netdev = dev;
+ return 0;
}
-static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/**
+ * called by device driver when removing device instance
+ * do generic HDLC cleanup
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_exit(SLMP_INFO *info)
{
- SLMP_INFO *info = dev->priv;
- if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__,
- info->netname, cmd );
- return sppp_do_ioctl(dev, ifr, cmd);
+ unregister_hdlc_device(info->netdev);
+ free_netdev(info->netdev);
+ info->netdev = NULL;
}
-#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
+#endif /* CONFIG_HDLC */
/* Return next bottom half action to perform.
@@ -2168,9 +2356,9 @@ void isr_txeom(SLMP_INFO * info, unsigned char status)
set_signals(info);
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef CONFIG_HDLC
if (info->netcount)
- sppp_tx_done(info);
+ hdlcdev_tx_done(info);
else
#endif
{
@@ -2358,12 +2546,12 @@ void isr_io_pin( SLMP_INFO *info, u16 status )
icount->dcd++;
if (status & SerialSignal_DCD) {
info->input_signal_events.dcd_up++;
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount)
- sppp_reopen(info->netdev);
-#endif
} else
info->input_signal_events.dcd_down++;
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlc_set_carrier(status & SerialSignal_DCD, info->netdev);
+#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
{
@@ -3616,9 +3804,8 @@ void add_device(SLMP_INFO *info)
info->irq_level,
info->max_frame_size );
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->dosyncppp)
- sppp_init(info);
+#ifdef CONFIG_HDLC
+ hdlcdev_init(info);
#endif
}
@@ -3804,9 +3991,8 @@ static void synclinkmp_cleanup(void)
info = synclinkmp_device_list;
while(info) {
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->dosyncppp)
- sppp_delete(info);
+#ifdef CONFIG_HDLC
+ hdlcdev_exit(info);
#endif
reset_port(info);
if ( info->port_num == 0 ) {
@@ -4823,10 +5009,12 @@ CheckAgain:
info->icount.rxcrc++;
framesize = 0;
-
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- info->netstats.rx_errors++;
- info->netstats.rx_frame_errors++;
+#ifdef CONFIG_HDLC
+ {
+ struct net_device_stats *stats = hdlc_stats(info->netdev);
+ stats->rx_errors++;
+ stats->rx_frame_errors++;
+ }
#endif
}
@@ -4862,11 +5050,9 @@ CheckAgain:
index = 0;
}
-#ifdef CONFIG_SYNCLINK_SYNCPPP
- if (info->netcount) {
- /* pass frame to syncppp device */
- sppp_rx_done(info,info->tmp_rx_buf,framesize);
- }
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlcdev_rx(info,info->tmp_rx_buf,framesize);
else
#endif
{
@@ -5384,9 +5570,9 @@ void tx_timeout(unsigned long context)
spin_unlock_irqrestore(&info->lock,flags);
-#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef CONFIG_HDLC
if (info->netcount)
- sppp_tx_done(info);
+ hdlcdev_tx_done(info);
else
#endif
bh_transmit(info);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 91f530c6170ee..2b28688b36ead 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -142,6 +142,7 @@ static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *);
static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
+static int ptmx_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
@@ -377,6 +378,19 @@ static struct file_operations tty_fops = {
.fasync = tty_fasync,
};
+#ifdef CONFIG_UNIX98_PTYS
+static struct file_operations ptmx_fops = {
+ .llseek = no_llseek,
+ .read = tty_read,
+ .write = tty_write,
+ .poll = tty_poll,
+ .ioctl = tty_ioctl,
+ .open = ptmx_open,
+ .release = tty_release,
+ .fasync = tty_fasync,
+};
+#endif
+
static struct file_operations console_fops = {
.llseek = no_llseek,
.read = tty_read,
@@ -749,6 +763,17 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t
return tty_write(file, buf, count, ppos);
}
+static char ptychar[] = "pqrstuvwxyzabcde";
+
+static inline void pty_line_name(struct tty_driver *driver, int index, char *p)
+{
+ int i = index + driver->name_base;
+ /* ->name is initialized to "ttyp", but "tty" is expected */
+ sprintf(p, "%s%c%x",
+ driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
+ ptychar[i >> 4 & 0xf], i & 0xf);
+}
+
static inline void tty_line_name(struct tty_driver *driver, int index, char *p)
{
sprintf(p, "%s%d", driver->name, index + driver->name_base);
@@ -1358,53 +1383,13 @@ retry_open:
return -ENODEV;
}
-#ifdef CONFIG_UNIX98_PTYS
- if (device == MKDEV(TTYAUX_MAJOR,2)) {
- int idr_ret;
-
- /* find a device that is not in use. */
- down(&allocated_ptys_lock);
- if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
- up(&allocated_ptys_lock);
- return -ENOMEM;
- }
- idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
- if (idr_ret < 0) {
- up(&allocated_ptys_lock);
- if (idr_ret == -EAGAIN)
- return -ENOMEM;
- return -EIO;
- }
- if (index >= pty_limit) {
- idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
- return -EIO;
- }
- up(&allocated_ptys_lock);
-
- driver = ptm_driver;
- retval = init_dev(driver, index, &tty);
- if (retval) {
- down(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
- return retval;
- }
-
- set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
- if (devpts_pty_new(tty->link))
- retval = -ENOMEM;
- } else
-#endif
- {
- driver = get_tty_driver(device, &index);
- if (!driver)
- return -ENODEV;
+ driver = get_tty_driver(device, &index);
+ if (!driver)
+ return -ENODEV;
got_driver:
- retval = init_dev(driver, index, &tty);
- if (retval)
- return retval;
- }
+ retval = init_dev(driver, index, &tty);
+ if (retval)
+ return retval;
filp->private_data = tty;
file_move(filp, &tty->tty_files);
@@ -1431,15 +1416,6 @@ got_driver:
printk(KERN_DEBUG "error %d in opening %s...", retval,
tty->name);
#endif
-
-#ifdef CONFIG_UNIX98_PTYS
- if (index != -1) {
- down(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, index);
- up(&allocated_ptys_lock);
- }
-#endif
-
release_dev(filp);
if (retval != -ERESTARTSYS)
return retval;
@@ -1467,6 +1443,62 @@ got_driver:
return 0;
}
+#ifdef CONFIG_UNIX98_PTYS
+static int ptmx_open(struct inode * inode, struct file * filp)
+{
+ struct tty_struct *tty;
+ int retval;
+ int index;
+ int idr_ret;
+
+ nonseekable_open(inode, filp);
+
+ /* find a device that is not in use. */
+ down(&allocated_ptys_lock);
+ if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
+ up(&allocated_ptys_lock);
+ return -ENOMEM;
+ }
+ idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
+ if (idr_ret < 0) {
+ up(&allocated_ptys_lock);
+ if (idr_ret == -EAGAIN)
+ return -ENOMEM;
+ return -EIO;
+ }
+ if (index >= pty_limit) {
+ idr_remove(&allocated_ptys, index);
+ up(&allocated_ptys_lock);
+ return -EIO;
+ }
+ up(&allocated_ptys_lock);
+
+ retval = init_dev(ptm_driver, index, &tty);
+ if (retval)
+ goto out;
+
+ set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+ filp->private_data = tty;
+ file_move(filp, &tty->tty_files);
+
+ retval = -ENOMEM;
+ if (devpts_pty_new(tty->link))
+ goto out1;
+
+ check_tty_count(tty, "tty_open");
+ retval = ptm_driver->open(tty, filp);
+ if (!retval)
+ return 0;
+out1:
+ release_dev(filp);
+out:
+ down(&allocated_ptys_lock);
+ idr_remove(&allocated_ptys, index);
+ up(&allocated_ptys_lock);
+ return retval;
+}
+#endif
+
static int tty_release(struct inode * inode, struct file * filp)
{
lock_kernel();
@@ -2154,6 +2186,7 @@ static struct class_simple *tty_class;
void tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
+ char name[64];
dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
if (index >= driver->num) {
@@ -2165,13 +2198,11 @@ void tty_register_device(struct tty_driver *driver, unsigned index,
devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
"%s%d", driver->devfs_name, index + driver->name_base);
- /* we don't care about the ptys */
- /* how nice to hide this behind some crappy interface.. */
- if (driver->type != TTY_DRIVER_TYPE_PTY) {
- char name[64];
+ if (driver->type == TTY_DRIVER_TYPE_PTY)
+ pty_line_name(driver, index, name);
+ else
tty_line_name(driver, index, name);
- class_simple_device_add(tty_class, dev, device, name);
- }
+ class_simple_device_add(tty_class, dev, device, name);
}
/**
@@ -2441,7 +2472,7 @@ static int __init tty_init(void)
class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
#ifdef CONFIG_UNIX98_PTYS
- cdev_init(&ptmx_cdev, &tty_fops);
+ cdev_init(&ptmx_cdev, &ptmx_fops);
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
panic("Couldn't register /dev/ptmx driver\n");
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 7956dda02f601..3cd02b60371c0 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -1981,12 +1981,16 @@ again:
hide_cursor(currcons);
while (!tty->stopped && count) {
- c = *buf;
+ int orig = *buf;
+ c = orig;
buf++;
n++;
count--;
- if (utf) {
+ /* Do no translation at all in control states */
+ if (vc_state != ESnormal) {
+ tc = c;
+ } else if (utf) {
/* Combine UTF-8 into Unicode */
/* Incomplete characters silently ignored */
if(c > 0x7f) {
@@ -2086,7 +2090,7 @@ again:
continue;
}
FLUSH
- do_con_trol(tty, currcons, c);
+ do_con_trol(tty, currcons, orig);
}
FLUSH
console_conditional_schedule();
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index a9dec9e98f3f7..4f109b7d75951 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -319,6 +319,12 @@ config MACHZ_WDT
To compile this driver as a module, choose M here: the
module will be called machzwd.
+# PowerPC Architecture
+
+config 8xx_WDT
+ tristate "MPC8xx Watchdog Timer"
+ depends on WATCHDOG && 8xx
+
# MIPS Architecture
config INDYDOG
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index c5f99d33260a3..c43e9990c52c9 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -37,3 +37,4 @@ obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
new file mode 100644
index 0000000000000..56d62ba7c6ce3
--- /dev/null
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -0,0 +1,164 @@
+/*
+ * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
+ *
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/8xx_immap.h>
+#include <asm/uaccess.h>
+#include <syslib/m8xx_wdt.h>
+
+static unsigned long wdt_opened;
+static int wdt_status;
+
+static void mpc8xx_wdt_handler_disable(void)
+{
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+ imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+
+ printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
+}
+
+static void mpc8xx_wdt_handler_enable(void)
+{
+ volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+ imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+
+ printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
+}
+
+static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &wdt_opened))
+ return -EBUSY;
+
+ m8xx_wdt_reset();
+ mpc8xx_wdt_handler_disable();
+
+ return 0;
+}
+
+static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
+{
+ m8xx_wdt_reset();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+ mpc8xx_wdt_handler_enable();
+#endif
+
+ clear_bit(0, &wdt_opened);
+
+ return 0;
+}
+
+static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t * ppos)
+{
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (len)
+ m8xx_wdt_reset();
+
+ return len;
+}
+
+static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int timeout;
+ static struct watchdog_info info = {
+ .options = WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "MPC8xx watchdog",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(wdt_status, (int *)arg))
+ return -EFAULT;
+ wdt_status &= ~WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_GETTEMP:
+ return -EOPNOTSUPP;
+
+ case WDIOC_SETOPTIONS:
+ return -EOPNOTSUPP;
+
+ case WDIOC_KEEPALIVE:
+ m8xx_wdt_reset();
+ wdt_status |= WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ return -EOPNOTSUPP;
+
+ case WDIOC_GETTIMEOUT:
+ timeout = m8xx_wdt_get_timeout();
+ if (put_user(timeout, (int *)arg))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static struct file_operations mpc8xx_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = mpc8xx_wdt_write,
+ .ioctl = mpc8xx_wdt_ioctl,
+ .open = mpc8xx_wdt_open,
+ .release = mpc8xx_wdt_release,
+};
+
+static struct miscdevice mpc8xx_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mpc8xx_wdt_fops,
+};
+
+static int __init mpc8xx_wdt_init(void)
+{
+ return misc_register(&mpc8xx_wdt_miscdev);
+}
+
+static void __exit mpc8xx_wdt_exit(void)
+{
+ misc_deregister(&mpc8xx_wdt_miscdev);
+
+ m8xx_wdt_reset();
+ mpc8xx_wdt_handler_enable();
+}
+
+module_init(mpc8xx_wdt_init);
+module_exit(mpc8xx_wdt_exit);
+
+MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
+MODULE_DESCRIPTION("MPC8xx watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index 9d5b5f4e5a7f7..7651deda928c3 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -674,8 +674,8 @@ out:
out_misc:
#ifdef CONFIG_WDT_501_PCI
misc_deregister(&temp_miscdev);
-#endif /* CONFIG_WDT_501_PCI */
out_rbt:
+#endif /* CONFIG_WDT_501_PCI */
unregister_reboot_notifier(&wdtpci_notifier);
out_irq:
free_irq(irq, &wdtpci_miscdev);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 331b5156da770..889f243fbd16d 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -69,6 +69,21 @@ config CPU_FREQ_GOV_USERSPACE
If in doubt, say Y.
+config CPU_FREQ_GOV_ONDEMAND
+ tristate "'ondemand' cpufreq policy governor"
+ depends on CPU_FREQ
+ help
+ 'ondemand' - This driver adds a dynamic cpufreq policy governor.
+ The governor does a periodic polling and
+ changes frequency based on the CPU utilization.
+ The support for this governor depends on CPU capability to
+ do fast frequency switching (i.e, very low latency frequency
+ transitions).
+
+ For details, take a look at linux/Documentation/cpu-freq.
+
+ If in doubt, say N.
+
config CPU_FREQ_24_API
bool "/proc/sys/cpu/ interface (2.4. / OLD)"
depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1eebf3c6edc38..50291abb48637 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
+obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
new file mode 100644
index 0000000000000..816c2a58a5f47
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -0,0 +1,424 @@
+/*
+ * drivers/cpufreq/cpufreq_ondemand.c
+ *
+ * Copyright (C) 2001 Russell King
+ * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
+ * Jun Nakajima <jun.nakajima@intel.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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/cpufreq.h>
+#include <linux/sysctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/config.h>
+#include <linux/kernel_stat.h>
+#include <linux/percpu.h>
+
+/*
+ * dbs is used in this file as a shortform for demandbased switching
+ * It helps to keep variable names smaller, simpler
+ */
+
+#define DEF_FREQUENCY_UP_THRESHOLD (80)
+#define MIN_FREQUENCY_UP_THRESHOLD (0)
+#define MAX_FREQUENCY_UP_THRESHOLD (100)
+
+#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
+#define MIN_FREQUENCY_DOWN_THRESHOLD (0)
+#define MAX_FREQUENCY_DOWN_THRESHOLD (100)
+
+/*
+ * The polling frequency of this governor depends on the capability of
+ * the processor. Default polling frequency is 1000 times the transition
+ * latency of the processor. The governor will work on any processor with
+ * transition latency <= 10mS, using appropriate sampling
+ * rate.
+ * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work.
+ * All times here are in uS.
+ */
+static unsigned int def_sampling_rate;
+#define MIN_SAMPLING_RATE (def_sampling_rate / 2)
+#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
+#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
+#define DEF_SAMPLING_DOWN_FACTOR (10)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define sampling_rate_in_HZ(x) ((x * HZ) / (1000 * 1000))
+
+static void do_dbs_timer(void *data);
+
+struct cpu_dbs_info_s {
+ struct cpufreq_policy *cur_policy;
+ unsigned int prev_cpu_idle_up;
+ unsigned int prev_cpu_idle_down;
+ unsigned int enable;
+};
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+
+static unsigned int dbs_enable; /* number of CPUs using this policy */
+
+static DECLARE_MUTEX (dbs_sem);
+static DECLARE_WORK (dbs_work, do_dbs_timer, NULL);
+
+struct dbs_tuners {
+ unsigned int sampling_rate;
+ unsigned int sampling_down_factor;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+};
+
+struct dbs_tuners dbs_tuners_ins = {
+ .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+ .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
+ .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
+};
+
+/************************** sysfs interface ************************/
+static ssize_t show_current_freq(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf (buf, "%u\n", policy->cur);
+}
+
+static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf (buf, "%u\n", MAX_SAMPLING_RATE);
+}
+
+static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
+}
+
+#define define_one_ro(_name) \
+static struct freq_attr _name = { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = show_##_name, \
+}
+
+define_one_ro(current_freq);
+define_one_ro(sampling_rate_max);
+define_one_ro(sampling_rate_min);
+
+/* cpufreq_ondemand Governor Tunables */
+#define show_one(file_name, object) \
+static ssize_t show_##file_name \
+(struct cpufreq_policy *unused, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
+}
+show_one(sampling_rate, sampling_rate);
+show_one(sampling_down_factor, sampling_down_factor);
+show_one(up_threshold, up_threshold);
+show_one(down_threshold, down_threshold);
+
+static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+ down(&dbs_sem);
+ if (ret != 1 )
+ goto out;
+
+ dbs_tuners_ins.sampling_down_factor = input;
+out:
+ up(&dbs_sem);
+ return count;
+}
+
+static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+ down(&dbs_sem);
+ if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE)
+ goto out;
+
+ dbs_tuners_ins.sampling_rate = input;
+out:
+ up(&dbs_sem);
+ return count;
+}
+
+static ssize_t store_up_threshold(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+ down(&dbs_sem);
+ if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
+ input < MIN_FREQUENCY_UP_THRESHOLD ||
+ input <= dbs_tuners_ins.down_threshold)
+ goto out;
+
+ dbs_tuners_ins.up_threshold = input;
+out:
+ up(&dbs_sem);
+ return count;
+}
+
+static ssize_t store_down_threshold(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+ down(&dbs_sem);
+ if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD ||
+ input < MIN_FREQUENCY_DOWN_THRESHOLD ||
+ input >= dbs_tuners_ins.up_threshold)
+ goto out;
+
+ dbs_tuners_ins.down_threshold = input;
+out:
+ up(&dbs_sem);
+ return count;
+}
+
+#define define_one_rw(_name) \
+static struct freq_attr _name = { \
+ .attr = { .name = __stringify(_name), .mode = 0644 }, \
+ .show = show_##_name, \
+ .store = store_##_name, \
+}
+
+define_one_rw(sampling_rate);
+define_one_rw(sampling_down_factor);
+define_one_rw(up_threshold);
+define_one_rw(down_threshold);
+
+static struct attribute * dbs_attributes[] = {
+ &current_freq.attr,
+ &sampling_rate_max.attr,
+ &sampling_rate_min.attr,
+ &sampling_rate.attr,
+ &sampling_down_factor.attr,
+ &up_threshold.attr,
+ &down_threshold.attr,
+ NULL
+};
+
+static struct attribute_group dbs_attr_group = {
+ .attrs = dbs_attributes,
+ .name = "ondemand",
+};
+
+/************************** sysfs end ************************/
+
+static void dbs_check_cpu(int cpu)
+{
+ unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
+ unsigned int freq_down_step;
+ unsigned int freq_down_sampling_rate;
+ static int down_skip[NR_CPUS];
+ struct cpu_dbs_info_s *this_dbs_info;
+
+ this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ if (!this_dbs_info->enable)
+ return;
+
+ /*
+ * The default safe range is 20% to 80%
+ * Every sampling_rate, we check
+ * - If current idle time is less than 20%, then we try to
+ * increase frequency
+ * Every sampling_rate*sampling_down_factor, we check
+ * - If current idle time is more than 80%, then we try to
+ * decrease frequency
+ *
+ * Any frequency increase takes it to the maximum frequency.
+ * Frequency reduction happens at minimum steps of
+ * 5% of max_frequency
+ */
+ /* Check for frequency increase */
+ idle_ticks = kstat_cpu(cpu).cpustat.idle -
+ this_dbs_info->prev_cpu_idle_up;
+ this_dbs_info->prev_cpu_idle_up = kstat_cpu(cpu).cpustat.idle;
+
+ up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
+ sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate) / 100;
+
+ if (idle_ticks < up_idle_ticks) {
+ __cpufreq_driver_target(this_dbs_info->cur_policy,
+ this_dbs_info->cur_policy->max,
+ CPUFREQ_RELATION_H);
+ down_skip[cpu] = 0;
+ this_dbs_info->prev_cpu_idle_down = kstat_cpu(cpu).cpustat.idle;
+ return;
+ }
+
+ /* Check for frequency decrease */
+ down_skip[cpu]++;
+ if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
+ return;
+
+ idle_ticks = kstat_cpu(cpu).cpustat.idle -
+ this_dbs_info->prev_cpu_idle_down;
+ down_skip[cpu] = 0;
+ this_dbs_info->prev_cpu_idle_down = kstat_cpu(cpu).cpustat.idle;
+
+ freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
+ dbs_tuners_ins.sampling_down_factor;
+ down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
+ sampling_rate_in_HZ(freq_down_sampling_rate) / 100;
+
+ if (idle_ticks > down_idle_ticks ) {
+ freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100;
+ __cpufreq_driver_target(this_dbs_info->cur_policy,
+ this_dbs_info->cur_policy->cur - freq_down_step,
+ CPUFREQ_RELATION_H);
+ return;
+ }
+}
+
+static void do_dbs_timer(void *data)
+{
+ int i;
+ down(&dbs_sem);
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_online(i))
+ dbs_check_cpu(i);
+ schedule_delayed_work(&dbs_work,
+ sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+ up(&dbs_sem);
+}
+
+static inline void dbs_timer_init(void)
+{
+ INIT_WORK(&dbs_work, do_dbs_timer, NULL);
+ schedule_work(&dbs_work);
+ return;
+}
+
+static inline void dbs_timer_exit(void)
+{
+ cancel_delayed_work(&dbs_work);
+ return;
+}
+
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ unsigned int event)
+{
+ unsigned int cpu = policy->cpu;
+ struct cpu_dbs_info_s *this_dbs_info;
+
+ this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+ switch (event) {
+ case CPUFREQ_GOV_START:
+ if ((!cpu_online(cpu)) ||
+ (!policy->cur))
+ return -EINVAL;
+
+ if (policy->cpuinfo.transition_latency >
+ (TRANSITION_LATENCY_LIMIT * 1000))
+ return -EINVAL;
+ if (this_dbs_info->enable) /* Already enabled */
+ break;
+
+ down(&dbs_sem);
+ this_dbs_info->cur_policy = policy;
+
+ this_dbs_info->prev_cpu_idle_up =
+ kstat_cpu(cpu).cpustat.idle;
+ this_dbs_info->prev_cpu_idle_down =
+ kstat_cpu(cpu).cpustat.idle;
+ this_dbs_info->enable = 1;
+ sysfs_create_group(&policy->kobj, &dbs_attr_group);
+ dbs_enable++;
+ /*
+ * Start the timerschedule work, when this governor
+ * is used for first time
+ */
+ if (dbs_enable == 1) {
+ /* policy latency is in nS. Convert it to uS first */
+ def_sampling_rate = (policy->cpuinfo.transition_latency / 1000) *
+ DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
+ dbs_tuners_ins.sampling_rate = def_sampling_rate;
+
+ dbs_timer_init();
+ }
+
+ up(&dbs_sem);
+ break;
+
+ case CPUFREQ_GOV_STOP:
+ down(&dbs_sem);
+ this_dbs_info->enable = 0;
+ sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+ dbs_enable--;
+ /*
+ * Stop the timerschedule work, when this governor
+ * is used for first time
+ */
+ if (dbs_enable == 0)
+ dbs_timer_exit();
+
+ up(&dbs_sem);
+
+ break;
+
+ case CPUFREQ_GOV_LIMITS:
+ down(&dbs_sem);
+ if (policy->max < this_dbs_info->cur_policy->cur)
+ __cpufreq_driver_target(
+ this_dbs_info->cur_policy,
+ policy->max, CPUFREQ_RELATION_H);
+ else if (policy->min > this_dbs_info->cur_policy->cur)
+ __cpufreq_driver_target(
+ this_dbs_info->cur_policy,
+ policy->min, CPUFREQ_RELATION_L);
+ up(&dbs_sem);
+ break;
+ }
+ return 0;
+}
+
+struct cpufreq_governor cpufreq_gov_dbs = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .owner = THIS_MODULE,
+};
+EXPORT_SYMBOL(cpufreq_gov_dbs);
+
+static int __init cpufreq_gov_dbs_init(void)
+{
+ return cpufreq_register_governor(&cpufreq_gov_dbs);
+}
+
+static void __exit cpufreq_gov_dbs_exit(void)
+{
+ /* Make sure that the scheduled work is indeed not running */
+ flush_scheduled_work();
+
+ cpufreq_unregister_governor(&cpufreq_gov_dbs);
+}
+
+
+MODULE_AUTHOR ("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
+MODULE_DESCRIPTION ("'cpufreq_ondemand' - A dynamic cpufreq governor for "
+ "Low Latency Frequency Transition capable processors");
+MODULE_LICENSE ("GPL");
+
+module_init(cpufreq_gov_dbs_init);
+module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c
index 2997929306a42..e170b2a786b91 100644
--- a/drivers/i2c/chips/asb100.c
+++ b/drivers/i2c/chips/asb100.c
@@ -520,9 +520,9 @@ static ssize_t show_vid(struct device *dev, char *buf)
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
}
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_in0_ref)
+device_create_file(&client->dev, &dev_attr_cpu0_vid)
/* VRM */
static ssize_t show_vrm(struct device *dev, char *buf)
diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c
index aa735e7cf2944..c7c068b820712 100644
--- a/drivers/i2c/chips/it87.c
+++ b/drivers/i2c/chips/it87.c
@@ -571,9 +571,9 @@ show_vid_reg(struct device *dev, char *buf)
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_in0_ref)
+device_create_file(&client->dev, &dev_attr_cpu0_vid)
/* This function is called when:
* it87_driver is inserted (when this module is loaded), for each
diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c
index 40385ffd8b918..b3cab5fa9d8c6 100644
--- a/drivers/i2c/chips/lm78.c
+++ b/drivers/i2c/chips/lm78.c
@@ -423,7 +423,7 @@ static ssize_t show_vid(struct device *dev, char *buf)
struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%d\n", VID_FROM_REG(data->vid));
}
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
/* Alarms */
static ssize_t show_alarms(struct device *dev, char *buf)
@@ -615,7 +615,7 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_fan3_min);
device_create_file(&new_client->dev, &dev_attr_fan3_div);
device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_in0_ref);
+ device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
return 0;
diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c
index d8cecb1739882..757520f7562cd 100644
--- a/drivers/i2c/chips/lm85.c
+++ b/drivers/i2c/chips/lm85.c
@@ -465,7 +465,7 @@ static ssize_t show_vid_reg(struct device *dev, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, char *buf)
{
@@ -874,7 +874,7 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
device_create_file(&new_client->dev, &dev_attr_temp2_max);
device_create_file(&new_client->dev, &dev_attr_temp3_max);
device_create_file(&new_client->dev, &dev_attr_vrm);
- device_create_file(&new_client->dev, &dev_attr_in0_ref);
+ device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c
index 90a48e77cff8c..5c3ade5b6498d 100644
--- a/drivers/i2c/chips/w83627hf.c
+++ b/drivers/i2c/chips/w83627hf.c
@@ -635,9 +635,9 @@ show_vid_reg(struct device *dev, char *buf)
struct w83627hf_data *data = w83627hf_update_device(dev);
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_in0_ref)
+device_create_file(&client->dev, &dev_attr_cpu0_vid)
static ssize_t
show_vrm_reg(struct device *dev, char *buf)
diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c
index 9612fab5655c5..063d34a0de9b3 100644
--- a/drivers/i2c/chips/w83781d.c
+++ b/drivers/i2c/chips/w83781d.c
@@ -503,9 +503,9 @@ show_vid_reg(struct device *dev, char *buf)
}
static
-DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
+DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_in0_ref);
+device_create_file(&client->dev, &dev_attr_cpu0_vid);
static ssize_t
show_vrm_reg(struct device *dev, char *buf)
{
diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h
index 1557a47ff9abb..603018e44eb01 100644
--- a/drivers/ide/legacy/qd65xx.h
+++ b/drivers/ide/legacy/qd65xx.h
@@ -47,10 +47,10 @@
/* Drive specific timing taken from DOS driver v3.7 */
struct qd65xx_timing_s {
- char offset; /* ofset from the beginning of Model Number" */
+ s8 offset; /* ofset from the beginning of Model Number" */
char model[4]; /* 4 chars from Model number, no conversion */
- short active; /* active time */
- short recovery; /* recovery time */
+ s16 active; /* active time */
+ s16 recovery; /* recovery time */
} qd65xx_timing [] = {
{ 30, "2040", 110, 225 }, /* Conner CP30204 */
{ 30, "2045", 135, 225 }, /* Conner CP30254 */
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 48a0ad5871600..58a7dec8faebe 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -6,7 +6,7 @@
* Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
*
* Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c
- * Copyright (c) 1999 Alex deVries <adevries@thepuffingroup.com>
+ * Copyright (c) 1999 Alex deVries <alex@onefishtwo.ca>
* Copyright (c) 1999-2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
* Copyright (c) 2000-2001 Thomas Marteau <marteaut@esiee.fr>
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 235f28a46551c..3a6acdeada5c9 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -752,70 +752,70 @@ setup_avm_pcipnp(struct IsdnCard *card)
cs->hw.avm.cfg_reg = card->para[1];
cs->irq = card->para[0];
cs->subtyp = AVM_FRITZ_PNP;
- } else {
+ goto ready;
+ }
#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_avm_d = NULL;
- if ((pnp_avm_c = pnp_find_card(
+ if (isapnp_present()) {
+ struct pnp_dev *pnp_avm_d = NULL;
+ if ((pnp_avm_c = pnp_find_card(
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+ if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
- if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
- int err;
-
- pnp_disable_dev(pnp_avm_d);
- err = pnp_activate_dev(pnp_avm_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- cs->hw.avm.cfg_reg =
- pnp_port_start(pnp_avm_d, 0);
- cs->irq = pnp_irq(pnp_avm_d, 0);
- if (!cs->irq) {
- printk(KERN_ERR "FritzPnP:No IRQ\n");
- return(0);
- }
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPnP:No IO address\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
+ ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+ int err;
+
+ pnp_disable_dev(pnp_avm_d);
+ err = pnp_activate_dev(pnp_avm_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ cs->hw.avm.cfg_reg =
+ pnp_port_start(pnp_avm_d, 0);
+ cs->irq = pnp_irq(pnp_avm_d, 0);
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPnP:No IRQ\n");
+ return(0);
}
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPnP:No IO address\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PNP;
+ goto ready;
}
- } else {
- printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
}
+ } else {
+ printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
+ }
#endif
#ifdef CONFIG_PCI
- if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_A1, dev_avm))) {
- cs->irq = dev_avm->irq;
- if (!cs->irq) {
- printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
- return(0);
- }
- if (pci_enable_device(dev_avm))
- return(0);
- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PCI;
- } else {
- printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+ cs->irq = dev_avm->irq;
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+ return(0);
+ }
+ if (pci_enable_device(dev_avm))
+ return(0);
+ cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
return(0);
}
- cs->irq_flags |= SA_SHIRQ;
+ cs->subtyp = AVM_FRITZ_PCI;
+ } else {
+ printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= SA_SHIRQ;
#else
- printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
- return (0);
+ printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
+ return (0);
#endif /* CONFIG_PCI */
- }
ready:
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
diff --git a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c
index 91392c4695a6d..b418d37c7cd00 100644
--- a/drivers/isdn/tpam/tpam_main.c
+++ b/drivers/isdn/tpam/tpam_main.c
@@ -23,7 +23,7 @@
/* Local functions prototypes */
static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *);
-static void __devexit tpam_unregister_card(tpam_card *);
+static void __devexit tpam_unregister_card(struct pci_dev *, tpam_card *);
static void __devexit tpam_remove(struct pci_dev *);
static int __init tpam_init(void);
static void __exit tpam_exit(void);
@@ -86,13 +86,20 @@ u32 tpam_findchannel(tpam_card *card, u32 ncoid) {
*/
static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
tpam_card *card, *c;
- int i;
+ int i, err;
+
+ if (pci_enable_device(dev)) {
+ printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
+ pci_name(dev));
+ return -ENODEV;
+ }
/* allocate memory for the board structure */
if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) {
printk(KERN_ERR "TurboPAM: tpam_register_card: "
"kmalloc failed!\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_out_disable_dev;
}
memset((char *)card, 0, sizeof(tpam_card));
@@ -106,8 +113,8 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
card->interface.id, card)) {
printk(KERN_ERR "TurboPAM: tpam_register_card: "
"could not request irq %d\n", card->irq);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_free_card;
}
/* remap board memory */
@@ -115,9 +122,8 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
0x800000))) {
printk(KERN_ERR "TurboPAM: tpam_register_card: "
"unable to remap bar0\n");
- free_irq(card->irq, card);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_free_irq;
}
/* reset the board */
@@ -150,10 +156,8 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
if (!register_isdn(&card->interface)) {
printk(KERN_ERR "TurboPAM: tpam_register_card: "
"unable to register %s\n", card->interface.id);
- free_irq(card->irq, card);
- iounmap((void *)card->bar0);
- kfree(card);
- return -EIO;
+ err = -EIO;
+ goto err_out_iounmap;
}
card->id = card->interface.channels;
@@ -195,6 +199,19 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
pci_set_drvdata(dev, card);
return 0;
+
+err_out_iounmap:
+ iounmap((void *)card->bar0);
+
+err_out_free_irq:
+ free_irq(card->irq, card);
+
+err_out_free_card:
+ kfree(card);
+
+err_out_disable_dev:
+ pci_disable_device(dev);
+ return err;
}
/*
@@ -202,7 +219,7 @@ static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id
*
* card: the board.
*/
-static void __devexit tpam_unregister_card(tpam_card *card) {
+static void __devexit tpam_unregister_card(struct pci_dev *pcidev, tpam_card *card) {
isdn_ctrl cmd;
/* prevent the ISDN link layer that the driver will be unloaded */
@@ -215,6 +232,8 @@ static void __devexit tpam_unregister_card(tpam_card *card) {
/* release mapped memory */
iounmap((void *)card->bar0);
+
+ pci_disable_device(pcidev);
}
/*
@@ -235,7 +254,7 @@ static void __devexit tpam_remove(struct pci_dev *pcidev) {
}
/* unregister each board */
- tpam_unregister_card(card);
+ tpam_unregister_card(pcidev, card);
/* and free the board structure itself */
kfree(card);
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index c0ab8589b634f..27ca59bf038a3 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -326,7 +326,7 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo
input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1));
input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
- if (nb >= 4)
+ if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD)
input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1));
input_report_rel(&adbhid[id]->input, REL_X,
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 87261d37f7a5c..2bf58c928b06b 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -85,6 +85,24 @@ config MD_RAID1
If unsure, say Y.
+config MD_RAID10
+ tristate "RAID-10 (mirrored striping) mode (EXPERIMENTAL)"
+ depends on BLK_DEV_MD && EXPERIMENTAL
+ ---help---
+ RAID-10 provides a combination of striping (RAID-0) and
+ mirroring (RAID-1) with easier configuration and more flexable
+ layout.
+ Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to
+ be the same size (or atleast, only as much as the smallest device
+ will be used).
+ RAID-10 provides a variety of layouts that provide different levels
+ of redundancy and performance.
+
+ RAID-10 requires mdadm-1.7.0 or later, available at:
+
+ ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/
+
+
config MD_RAID5
tristate "RAID-4/RAID-5 mode"
depends on BLK_DEV_MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 4f3ae7735fe6d..e1b176505438b 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -20,6 +20,7 @@ hostprogs-y := mktables
obj-$(CONFIG_MD_LINEAR) += linear.o
obj-$(CONFIG_MD_RAID0) += raid0.o
obj-$(CONFIG_MD_RAID1) += raid1.o
+obj-$(CONFIG_MD_RAID10) += raid10.o
obj-$(CONFIG_MD_RAID5) += raid5.o xor.o
obj-$(CONFIG_MD_RAID6) += raid6.o xor.o
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0cdce1ed3e320..fb0e8f5b9a365 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -406,7 +406,7 @@ static int read_disk_sb(mdk_rdev_t * rdev)
return 0;
fail:
- printk(KERN_ERR "md: disabled device %s, could not read superblock.\n",
+ printk(KERN_WARNING "md: disabled device %s, could not read superblock.\n",
bdevname(rdev->bdev,b));
return -EINVAL;
}
@@ -1075,20 +1075,24 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
/*
* prevent the device from being mounted, repartitioned or
* otherwise reused by a RAID array (or any other kernel
- * subsystem), by opening the device. [simply getting an
- * inode is not enough, the SCSI module usage code needs
- * an explicit open() on the device]
+ * subsystem), by bd_claiming the device.
*/
static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
{
int err = 0;
struct block_device *bdev;
+ char b[BDEVNAME_SIZE];
bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
- if (IS_ERR(bdev))
+ if (IS_ERR(bdev)) {
+ printk(KERN_ERR "md: could not open %s.\n",
+ __bdevname(dev, b));
return PTR_ERR(bdev);
+ }
err = bd_claim(bdev, rdev);
if (err) {
+ printk(KERN_ERR "md: could not bd_claim %s.\n",
+ bdevname(bdev, b));
blkdev_put(bdev);
return err;
}
@@ -1150,10 +1154,7 @@ static void export_array(mddev_t *mddev)
static void print_desc(mdp_disk_t *desc)
{
- char b[BDEVNAME_SIZE];
-
- printk(" DISK<N:%d,%s(%d,%d),R:%d,S:%d>\n", desc->number,
- __bdevname(MKDEV(desc->major, desc->minor), b),
+ printk(" DISK<N:%d,(%d,%d),R:%d,S:%d>\n", desc->number,
desc->major,desc->minor,desc->raid_disk,desc->state);
}
@@ -1345,8 +1346,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL);
if (!rdev) {
- printk(KERN_ERR "md: could not alloc mem for %s!\n",
- __bdevname(newdev, b));
+ printk(KERN_ERR "md: could not alloc mem for new device!\n");
return ERR_PTR(-ENOMEM);
}
memset(rdev, 0, sizeof(*rdev));
@@ -1355,11 +1355,9 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
goto abort_free;
err = lock_rdev(rdev, newdev);
- if (err) {
- printk(KERN_ERR "md: could not lock %s.\n",
- __bdevname(newdev, b));
+ if (err)
goto abort_free;
- }
+
rdev->desc_nr = -1;
rdev->faulty = 0;
rdev->in_sync = 0;
@@ -1648,6 +1646,8 @@ static int do_md_run(mddev_t * mddev)
mddev->pers = pers[pnum];
spin_unlock(&pers_lock);
+ mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
+
err = mddev->pers->run(mddev);
if (err) {
printk(KERN_ERR "md: pers->run() failed ...\n");
@@ -1915,11 +1915,9 @@ static int autostart_array(dev_t startdev)
mdk_rdev_t *start_rdev = NULL, *rdev;
start_rdev = md_import_device(startdev, 0, 0);
- if (IS_ERR(start_rdev)) {
- printk(KERN_WARNING "md: could not import %s!\n",
- __bdevname(startdev, b));
+ if (IS_ERR(start_rdev))
return err;
- }
+
/* NOTE: this can only work for 0.90.0 superblocks */
sb = (mdp_super_t*)page_address(start_rdev->sb_page);
@@ -1950,12 +1948,9 @@ static int autostart_array(dev_t startdev)
if (MAJOR(dev) != desc->major || MINOR(dev) != desc->minor)
continue;
rdev = md_import_device(dev, 0, 0);
- if (IS_ERR(rdev)) {
- printk(KERN_WARNING "md: could not import %s,"
- " trying to run array nevertheless.\n",
- __bdevname(dev, b));
+ if (IS_ERR(rdev))
continue;
- }
+
list_add(&rdev->same_set, &pending_raid_disks);
}
@@ -2187,42 +2182,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
return 0;
}
-static int hot_generate_error(mddev_t * mddev, dev_t dev)
-{
- char b[BDEVNAME_SIZE];
- struct request_queue *q;
- mdk_rdev_t *rdev;
-
- if (!mddev->pers)
- return -ENODEV;
-
- printk(KERN_INFO "md: trying to generate %s error in %s ... \n",
- __bdevname(dev, b), mdname(mddev));
-
- rdev = find_rdev(mddev, dev);
- if (!rdev) {
- /* MD_BUG(); */ /* like hell - it's not a driver bug */
- return -ENXIO;
- }
-
- if (rdev->desc_nr == -1) {
- MD_BUG();
- return -EINVAL;
- }
- if (!rdev->in_sync)
- return -ENODEV;
-
- q = bdev_get_queue(rdev->bdev);
- if (!q) {
- MD_BUG();
- return -ENODEV;
- }
- printk(KERN_INFO "md: okay, generating error!\n");
-// q->oneshot_error = 1; // disabled for now
-
- return 0;
-}
-
static int hot_remove_disk(mddev_t * mddev, dev_t dev)
{
char b[BDEVNAME_SIZE];
@@ -2231,9 +2190,6 @@ static int hot_remove_disk(mddev_t * mddev, dev_t dev)
if (!mddev->pers)
return -ENODEV;
- printk(KERN_INFO "md: trying to remove %s from %s ... \n",
- __bdevname(dev, b), mdname(mddev));
-
rdev = find_rdev(mddev, dev);
if (!rdev)
return -ENXIO;
@@ -2261,9 +2217,6 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
if (!mddev->pers)
return -ENODEV;
- printk(KERN_INFO "md: trying to hot-add %s to %s ... \n",
- __bdevname(dev, b), mdname(mddev));
-
if (mddev->major_version != 0) {
printk(KERN_WARNING "%s: HOT_ADD may only be used with"
" version-0 superblocks.\n",
@@ -2523,7 +2476,6 @@ static int set_disk_faulty(mddev_t *mddev, dev_t dev)
static int md_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- char b[BDEVNAME_SIZE];
int err = 0;
void __user *argp = (void __user *)arg;
struct hd_geometry __user *loc = argp;
@@ -2582,8 +2534,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
}
err = autostart_array(new_decode_dev(arg));
if (err) {
- printk(KERN_WARNING "md: autostart %s failed!\n",
- __bdevname(arg, b));
+ printk(KERN_WARNING "md: autostart failed!\n");
goto abort;
}
goto done;
@@ -2724,9 +2675,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
err = add_new_disk(mddev, &info);
goto done_unlock;
}
- case HOT_GENERATE_ERROR:
- err = hot_generate_error(mddev, new_decode_dev(arg));
- goto done_unlock;
+
case HOT_REMOVE_DISK:
err = hot_remove_disk(mddev, new_decode_dev(arg));
goto done_unlock;
@@ -2953,6 +2902,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
if (!mddev->pers->error_handler)
return;
mddev->pers->error_handler(mddev,rdev);
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
}
@@ -2985,7 +2935,11 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
unsigned long max_blocks, resync, res, dt, db, rt;
resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
- max_blocks = mddev->size;
+
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ max_blocks = mddev->resync_max_sectors >> 1;
+ else
+ max_blocks = mddev->size;
/*
* Should not happen.
@@ -3221,11 +3175,6 @@ int unregister_md_personality(int pnum)
return 0;
}
-void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors)
-{
- rdev->bdev->bd_contains->bd_disk->sync_io += nr_sectors;
-}
-
static int is_mddev_idle(mddev_t *mddev)
{
mdk_rdev_t * rdev;
@@ -3238,8 +3187,12 @@ static int is_mddev_idle(mddev_t *mddev)
struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
curr_events = disk_stat_read(disk, read_sectors) +
disk_stat_read(disk, write_sectors) -
- disk->sync_io;
- if ((curr_events - rdev->last_events) > 32) {
+ atomic_read(&disk->sync_io);
+ /* Allow some slack between valud of curr_events and last_events,
+ * as there are some uninteresting races.
+ * Note: the following is an unsigned comparison.
+ */
+ if ((curr_events - rdev->last_events + 32) > 64) {
rdev->last_events = curr_events;
idle = 0;
}
@@ -3373,7 +3326,14 @@ static void md_do_sync(mddev_t *mddev)
}
} while (mddev->curr_resync < 2);
- max_sectors = mddev->size << 1;
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ /* resync follows the size requested by the personality,
+ * which default to physical size, but can be virtual size
+ */
+ max_sectors = mddev->resync_max_sectors;
+ else
+ /* recovery follows the physical size of devices */
+ max_sectors = mddev->size << 1;
printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
@@ -3731,7 +3691,6 @@ void md_autodetect_dev(dev_t dev)
static void autostart_arrays(int part)
{
- char b[BDEVNAME_SIZE];
mdk_rdev_t *rdev;
int i;
@@ -3741,11 +3700,9 @@ static void autostart_arrays(int part)
dev_t dev = detected_devices[i];
rdev = md_import_device(dev,0, 0);
- if (IS_ERR(rdev)) {
- printk(KERN_ALERT "md: could not import %s!\n",
- __bdevname(dev, b));
+ if (IS_ERR(rdev))
continue;
- }
+
if (rdev->faulty) {
MD_BUG();
continue;
@@ -3796,7 +3753,6 @@ module_exit(md_exit)
EXPORT_SYMBOL(register_md_personality);
EXPORT_SYMBOL(unregister_md_personality);
EXPORT_SYMBOL(md_error);
-EXPORT_SYMBOL(md_sync_acct);
EXPORT_SYMBOL(md_done_sync);
EXPORT_SYMBOL(md_write_start);
EXPORT_SYMBOL(md_write_end);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 1deaa34434994..179dd05ca0a87 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -24,10 +24,6 @@
#include <linux/raid/raid1.h>
-#define MAJOR_NR MD_MAJOR
-#define MD_DRIVER
-#define MD_PERSONALITY
-
/*
* Number of guaranteed r1bios in case of extreme VM load:
*/
@@ -44,13 +40,12 @@ static void * r1bio_pool_alloc(int gfp_flags, void *data)
{
struct pool_info *pi = data;
r1bio_t *r1_bio;
+ int size = offsetof(r1bio_t, bios[pi->raid_disks]);
/* allocate a r1bio with room for raid_disks entries in the bios array */
- r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*pi->raid_disks,
- gfp_flags);
+ r1_bio = kmalloc(size, gfp_flags);
if (r1_bio)
- memset(r1_bio, 0, sizeof(*r1_bio) +
- sizeof(struct bio*) * pi->raid_disks);
+ memset(r1_bio, 0, size);
else
unplug_slaves(pi->mddev);
@@ -104,7 +99,7 @@ static void * r1buf_pool_alloc(int gfp_flags, void *data)
bio->bi_io_vec[i].bv_page = page;
}
- r1_bio->master_bio = bio;
+ r1_bio->master_bio = NULL;
return r1_bio;
@@ -189,32 +184,6 @@ static inline void put_buf(r1bio_t *r1_bio)
spin_unlock_irqrestore(&conf->resync_lock, flags);
}
-static int map(mddev_t *mddev, mdk_rdev_t **rdevp)
-{
- conf_t *conf = mddev_to_conf(mddev);
- int i, disks = conf->raid_disks;
-
- /*
- * Later we do read balancing on the read side
- * now we use the first available disk.
- */
-
- spin_lock_irq(&conf->device_lock);
- for (i = 0; i < disks; i++) {
- mdk_rdev_t *rdev = conf->mirrors[i].rdev;
- if (rdev && rdev->in_sync) {
- *rdevp = rdev;
- atomic_inc(&rdev->nr_pending);
- spin_unlock_irq(&conf->device_lock);
- return i;
- }
- }
- spin_unlock_irq(&conf->device_lock);
-
- printk(KERN_ERR "raid1_map(): huh, no more operational devices?\n");
- return -1;
-}
-
static void reschedule_retry(r1bio_t *r1_bio)
{
unsigned long flags;
@@ -292,8 +261,9 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
* oops, read error:
*/
char b[BDEVNAME_SIZE];
- printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n",
- bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector);
+ if (printk_ratelimit())
+ printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n",
+ bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector);
reschedule_retry(r1_bio);
}
@@ -363,11 +333,11 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
*
* The rdev for the device selected will have nr_pending incremented.
*/
-static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio)
+static int read_balance(conf_t *conf, r1bio_t *r1_bio)
{
const unsigned long this_sector = r1_bio->sector;
int new_disk = conf->last_used, disk = new_disk;
- const int sectors = bio->bi_size >> 9;
+ const int sectors = r1_bio->sectors;
sector_t new_distance, current_distance;
spin_lock_irq(&conf->device_lock);
@@ -378,14 +348,14 @@ static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio)
*/
if (conf->mddev->recovery_cp < MaxSector &&
(this_sector + sectors >= conf->next_resync)) {
- /* make sure that disk is operational */
+ /* Choose the first operation device, for consistancy */
new_disk = 0;
while (!conf->mirrors[new_disk].rdev ||
!conf->mirrors[new_disk].rdev->in_sync) {
new_disk++;
if (new_disk == conf->raid_disks) {
- new_disk = 0;
+ new_disk = -1;
break;
}
}
@@ -400,7 +370,7 @@ static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio)
new_disk = conf->raid_disks;
new_disk--;
if (new_disk == disk) {
- new_disk = conf->last_used;
+ new_disk = -1;
goto rb_out;
}
}
@@ -440,13 +410,13 @@ static int read_balance(conf_t *conf, struct bio *bio, r1bio_t *r1_bio)
} while (disk != conf->last_used);
rb_out:
- r1_bio->read_disk = new_disk;
- conf->next_seq_sect = this_sector + sectors;
- conf->last_used = new_disk;
- if (conf->mirrors[new_disk].rdev)
+ if (new_disk >= 0) {
+ conf->next_seq_sect = this_sector + sectors;
+ conf->last_used = new_disk;
atomic_inc(&conf->mirrors[new_disk].rdev->nr_pending);
+ }
spin_unlock_irq(&conf->device_lock);
return new_disk;
@@ -571,15 +541,26 @@ static int make_request(request_queue_t *q, struct bio * bio)
r1_bio->mddev = mddev;
r1_bio->sector = bio->bi_sector;
+ r1_bio->state = 0;
+
if (bio_data_dir(bio) == READ) {
/*
* read balancing logic:
*/
- mirror = conf->mirrors + read_balance(conf, bio, r1_bio);
+ int rdisk = read_balance(conf, r1_bio);
+
+ if (rdisk < 0) {
+ /* couldn't find anywhere to read from */
+ raid_end_bio_io(r1_bio);
+ return 0;
+ }
+ mirror = conf->mirrors + rdisk;
+
+ r1_bio->read_disk = rdisk;
read_bio = bio_clone(bio, GFP_NOIO);
- r1_bio->bios[r1_bio->read_disk] = read_bio;
+ r1_bio->bios[rdisk] = read_bio;
read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset;
read_bio->bi_bdev = mirror->rdev->bdev;
@@ -903,7 +884,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
atomic_inc(&conf->mirrors[i].rdev->nr_pending);
atomic_inc(&r1_bio->remaining);
- md_sync_acct(conf->mirrors[i].rdev, wbio->bi_size >> 9);
+ md_sync_acct(conf->mirrors[i].rdev->bdev, wbio->bi_size >> 9);
generic_make_request(wbio);
}
@@ -951,7 +932,7 @@ static void raid1d(mddev_t *mddev)
} else {
int disk;
bio = r1_bio->bios[r1_bio->read_disk];
- if ((disk=map(mddev, &rdev)) == -1) {
+ if ((disk=read_balance(conf, r1_bio)) == -1) {
printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
" read error for block %llu\n",
bdevname(bio->bi_bdev,b),
@@ -961,10 +942,12 @@ static void raid1d(mddev_t *mddev)
r1_bio->bios[r1_bio->read_disk] = NULL;
r1_bio->read_disk = disk;
r1_bio->bios[r1_bio->read_disk] = bio;
- printk(KERN_ERR "raid1: %s: redirecting sector %llu to"
- " another mirror\n",
- bdevname(rdev->bdev,b),
- (unsigned long long)r1_bio->sector);
+ rdev = conf->mirrors[disk].rdev;
+ if (printk_ratelimit())
+ printk(KERN_ERR "raid1: %s: redirecting sector %llu to"
+ " another mirror\n",
+ bdevname(rdev->bdev,b),
+ (unsigned long long)r1_bio->sector);
bio->bi_bdev = rdev->bdev;
bio->bi_sector = r1_bio->sector + rdev->data_offset;
bio->bi_rw = READ;
@@ -1143,7 +1126,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
bio = r1_bio->bios[disk];
r1_bio->sectors = nr_sectors;
- md_sync_acct(mirror->rdev, nr_sectors);
+ md_sync_acct(mirror->rdev->bdev, nr_sectors);
generic_make_request(bio);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
new file mode 100644
index 0000000000000..6c3fde9ba1923
--- /dev/null
+++ b/drivers/md/raid10.c
@@ -0,0 +1,1780 @@
+/*
+ * raid10.c : Multiple Devices driver for Linux
+ *
+ * Copyright (C) 2000-2004 Neil Brown
+ *
+ * RAID-10 support for md.
+ *
+ * Base on code in raid1.c. See raid1.c for futher copyright 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/raid/raid10.h>
+
+/*
+ * RAID10 provides a combination of RAID0 and RAID1 functionality.
+ * The layout of data is defined by
+ * chunk_size
+ * raid_disks
+ * near_copies (stored in low byte of layout)
+ * far_copies (stored in second byte of layout)
+ *
+ * The data to be stored is divided into chunks using chunksize.
+ * Each device is divided into far_copies sections.
+ * In each section, chunks are laid out in a style similar to raid0, but
+ * near_copies copies of each chunk is stored (each on a different drive).
+ * The starting device for each section is offset near_copies from the starting
+ * device of the previous section.
+ * Thus there are (near_copies*far_copies) of each chunk, and each is on a different
+ * drive.
+ * near_copies and far_copies must be at least one, and there product is at most
+ * raid_disks.
+ */
+
+/*
+ * Number of guaranteed r10bios in case of extreme VM load:
+ */
+#define NR_RAID10_BIOS 256
+
+static void unplug_slaves(mddev_t *mddev);
+
+static void * r10bio_pool_alloc(int gfp_flags, void *data)
+{
+ conf_t *conf = data;
+ r10bio_t *r10_bio;
+ int size = offsetof(struct r10bio_s, devs[conf->copies]);
+
+ /* allocate a r10bio with room for raid_disks entries in the bios array */
+ r10_bio = kmalloc(size, gfp_flags);
+ if (r10_bio)
+ memset(r10_bio, 0, size);
+ else
+ unplug_slaves(conf->mddev);
+
+ return r10_bio;
+}
+
+static void r10bio_pool_free(void *r10_bio, void *data)
+{
+ kfree(r10_bio);
+}
+
+#define RESYNC_BLOCK_SIZE (64*1024)
+//#define RESYNC_BLOCK_SIZE PAGE_SIZE
+#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
+#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
+#define RESYNC_WINDOW (2048*1024)
+
+/*
+ * When performing a resync, we need to read and compare, so
+ * we need as many pages are there are copies.
+ * When performing a recovery, we need 2 bios, one for read,
+ * one for write (we recover only one drive per r10buf)
+ *
+ */
+static void * r10buf_pool_alloc(int gfp_flags, void *data)
+{
+ conf_t *conf = data;
+ struct page *page;
+ r10bio_t *r10_bio;
+ struct bio *bio;
+ int i, j;
+ int nalloc;
+
+ r10_bio = r10bio_pool_alloc(gfp_flags, conf);
+ if (!r10_bio) {
+ unplug_slaves(conf->mddev);
+ return NULL;
+ }
+
+ if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
+ nalloc = conf->copies; /* resync */
+ else
+ nalloc = 2; /* recovery */
+
+ /*
+ * Allocate bios.
+ */
+ for (j = nalloc ; j-- ; ) {
+ bio = bio_alloc(gfp_flags, RESYNC_PAGES);
+ if (!bio)
+ goto out_free_bio;
+ r10_bio->devs[j].bio = bio;
+ }
+ /*
+ * Allocate RESYNC_PAGES data pages and attach them
+ * where needed.
+ */
+ for (j = 0 ; j < nalloc; j++) {
+ bio = r10_bio->devs[j].bio;
+ for (i = 0; i < RESYNC_PAGES; i++) {
+ page = alloc_page(gfp_flags);
+ if (unlikely(!page))
+ goto out_free_pages;
+
+ bio->bi_io_vec[i].bv_page = page;
+ }
+ }
+
+ return r10_bio;
+
+out_free_pages:
+ for ( ; i > 0 ; i--)
+ __free_page(bio->bi_io_vec[i-1].bv_page);
+ while (j--)
+ for (i = 0; i < RESYNC_PAGES ; i++)
+ __free_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
+ j = -1;
+out_free_bio:
+ while ( ++j < nalloc )
+ bio_put(r10_bio->devs[j].bio);
+ r10bio_pool_free(r10_bio, conf);
+ return NULL;
+}
+
+static void r10buf_pool_free(void *__r10_bio, void *data)
+{
+ int i;
+ conf_t *conf = data;
+ r10bio_t *r10bio = __r10_bio;
+ int j;
+
+ for (j=0; j < conf->copies; j++) {
+ struct bio *bio = r10bio->devs[j].bio;
+ if (bio) {
+ for (i = 0; i < RESYNC_PAGES; i++) {
+ __free_page(bio->bi_io_vec[i].bv_page);
+ bio->bi_io_vec[i].bv_page = NULL;
+ }
+ bio_put(bio);
+ }
+ }
+ r10bio_pool_free(r10bio, conf);
+}
+
+static void put_all_bios(conf_t *conf, r10bio_t *r10_bio)
+{
+ int i;
+
+ for (i = 0; i < conf->copies; i++) {
+ struct bio **bio = & r10_bio->devs[i].bio;
+ if (*bio)
+ bio_put(*bio);
+ *bio = NULL;
+ }
+}
+
+static inline void free_r10bio(r10bio_t *r10_bio)
+{
+ unsigned long flags;
+
+ conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+ /*
+ * Wake up any possible resync thread that waits for the device
+ * to go idle.
+ */
+ spin_lock_irqsave(&conf->resync_lock, flags);
+ if (!--conf->nr_pending) {
+ wake_up(&conf->wait_idle);
+ wake_up(&conf->wait_resume);
+ }
+ spin_unlock_irqrestore(&conf->resync_lock, flags);
+
+ put_all_bios(conf, r10_bio);
+ mempool_free(r10_bio, conf->r10bio_pool);
+}
+
+static inline void put_buf(r10bio_t *r10_bio)
+{
+ conf_t *conf = mddev_to_conf(r10_bio->mddev);
+ unsigned long flags;
+
+ mempool_free(r10_bio, conf->r10buf_pool);
+
+ spin_lock_irqsave(&conf->resync_lock, flags);
+ if (!conf->barrier)
+ BUG();
+ --conf->barrier;
+ wake_up(&conf->wait_resume);
+ wake_up(&conf->wait_idle);
+
+ if (!--conf->nr_pending) {
+ wake_up(&conf->wait_idle);
+ wake_up(&conf->wait_resume);
+ }
+ spin_unlock_irqrestore(&conf->resync_lock, flags);
+}
+
+static void reschedule_retry(r10bio_t *r10_bio)
+{
+ unsigned long flags;
+ mddev_t *mddev = r10_bio->mddev;
+ conf_t *conf = mddev_to_conf(mddev);
+
+ spin_lock_irqsave(&conf->device_lock, flags);
+ list_add(&r10_bio->retry_list, &conf->retry_list);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+
+ md_wakeup_thread(mddev->thread);
+}
+
+/*
+ * raid_end_bio_io() is called when we have finished servicing a mirrored
+ * operation and are ready to return a success/failure code to the buffer
+ * cache layer.
+ */
+static void raid_end_bio_io(r10bio_t *r10_bio)
+{
+ struct bio *bio = r10_bio->master_bio;
+
+ bio_endio(bio, bio->bi_size,
+ test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO);
+ free_r10bio(r10_bio);
+}
+
+/*
+ * Update disk head position estimator based on IRQ completion info.
+ */
+static inline void update_head_pos(int slot, r10bio_t *r10_bio)
+{
+ conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+ conf->mirrors[r10_bio->devs[slot].devnum].head_position =
+ r10_bio->devs[slot].addr + (r10_bio->sectors);
+}
+
+static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+{
+ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+ int slot, dev;
+ conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+ if (bio->bi_size)
+ return 1;
+
+ slot = r10_bio->read_slot;
+ dev = r10_bio->devs[slot].devnum;
+ /*
+ * this branch is our 'one mirror IO has finished' event handler:
+ */
+ if (!uptodate)
+ md_error(r10_bio->mddev, conf->mirrors[dev].rdev);
+ else
+ /*
+ * Set R10BIO_Uptodate in our master bio, so that
+ * we will return a good error code to the higher
+ * levels even if IO on some other mirrored buffer fails.
+ *
+ * The 'master' represents the composite IO operation to
+ * user-side. So if something waits for IO, then it will
+ * wait for the 'master' bio.
+ */
+ set_bit(R10BIO_Uptodate, &r10_bio->state);
+
+ update_head_pos(slot, r10_bio);
+
+ /*
+ * we have only one bio on the read side
+ */
+ if (uptodate)
+ raid_end_bio_io(r10_bio);
+ else {
+ /*
+ * oops, read error:
+ */
+ char b[BDEVNAME_SIZE];
+ if (printk_ratelimit())
+ printk(KERN_ERR "raid10: %s: rescheduling sector %llu\n",
+ bdevname(conf->mirrors[dev].rdev->bdev,b), (unsigned long long)r10_bio->sector);
+ reschedule_retry(r10_bio);
+ }
+
+ rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
+ return 0;
+}
+
+static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+{
+ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+ int slot, dev;
+ conf_t *conf = mddev_to_conf(r10_bio->mddev);
+
+ if (bio->bi_size)
+ return 1;
+
+ for (slot = 0; slot < conf->copies; slot++)
+ if (r10_bio->devs[slot].bio == bio)
+ break;
+ dev = r10_bio->devs[slot].devnum;
+
+ /*
+ * this branch is our 'one mirror IO has finished' event handler:
+ */
+ if (!uptodate)
+ md_error(r10_bio->mddev, conf->mirrors[dev].rdev);
+ else
+ /*
+ * Set R10BIO_Uptodate in our master bio, so that
+ * we will return a good error code for to the higher
+ * levels even if IO on some other mirrored buffer fails.
+ *
+ * The 'master' represents the composite IO operation to
+ * user-side. So if something waits for IO, then it will
+ * wait for the 'master' bio.
+ */
+ set_bit(R10BIO_Uptodate, &r10_bio->state);
+
+ update_head_pos(slot, r10_bio);
+
+ /*
+ *
+ * Let's see if all mirrored write operations have finished
+ * already.
+ */
+ if (atomic_dec_and_test(&r10_bio->remaining)) {
+ md_write_end(r10_bio->mddev);
+ raid_end_bio_io(r10_bio);
+ }
+
+ rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
+ return 0;
+}
+
+
+/*
+ * RAID10 layout manager
+ * Aswell as the chunksize and raid_disks count, there are two
+ * parameters: near_copies and far_copies.
+ * near_copies * far_copies must be <= raid_disks.
+ * Normally one of these will be 1.
+ * If both are 1, we get raid0.
+ * If near_copies == raid_disks, we get raid1.
+ *
+ * Chunks are layed out in raid0 style with near_copies copies of the
+ * first chunk, followed by near_copies copies of the next chunk and
+ * so on.
+ * If far_copies > 1, then after 1/far_copies of the array has been assigned
+ * as described above, we start again with a device offset of near_copies.
+ * So we effectively have another copy of the whole array further down all
+ * the drives, but with blocks on different drives.
+ * With this layout, and block is never stored twice on the one device.
+ *
+ * raid10_find_phys finds the sector offset of a given virtual sector
+ * on each device that it is on. If a block isn't on a device,
+ * that entry in the array is set to MaxSector.
+ *
+ * raid10_find_virt does the reverse mapping, from a device and a
+ * sector offset to a virtual address
+ */
+
+static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio)
+{
+ int n,f;
+ sector_t sector;
+ sector_t chunk;
+ sector_t stripe;
+ int dev;
+
+ int slot = 0;
+
+ /* now calculate first sector/dev */
+ chunk = r10bio->sector >> conf->chunk_shift;
+ sector = r10bio->sector & conf->chunk_mask;
+
+ chunk *= conf->near_copies;
+ stripe = chunk;
+ dev = sector_div(stripe, conf->raid_disks);
+
+ sector += stripe << conf->chunk_shift;
+
+ /* and calculate all the others */
+ for (n=0; n < conf->near_copies; n++) {
+ int d = dev;
+ sector_t s = sector;
+ r10bio->devs[slot].addr = sector;
+ r10bio->devs[slot].devnum = d;
+ slot++;
+
+ for (f = 1; f < conf->far_copies; f++) {
+ d += conf->near_copies;
+ if (d >= conf->raid_disks)
+ d -= conf->raid_disks;
+ s += conf->stride;
+ r10bio->devs[slot].devnum = d;
+ r10bio->devs[slot].addr = s;
+ slot++;
+ }
+ dev++;
+ if (dev >= conf->raid_disks) {
+ dev = 0;
+ sector += (conf->chunk_mask + 1);
+ }
+ }
+ BUG_ON(slot != conf->copies);
+}
+
+static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
+{
+ sector_t offset, chunk, vchunk;
+
+ while (sector > conf->stride) {
+ sector -= conf->stride;
+ if (dev < conf->near_copies)
+ dev += conf->raid_disks - conf->near_copies;
+ else
+ dev -= conf->near_copies;
+ }
+
+ offset = sector & conf->chunk_mask;
+ chunk = sector >> conf->chunk_shift;
+ vchunk = chunk * conf->raid_disks + dev;
+ sector_div(vchunk, conf->near_copies);
+ return (vchunk << conf->chunk_shift) + offset;
+}
+
+/**
+ * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged
+ * @q: request queue
+ * @bio: the buffer head that's been built up so far
+ * @biovec: the request that could be merged to it.
+ *
+ * Return amount of bytes we can accept at this offset
+ * If near_copies == raid_disk, there are no striping issues,
+ * but in that case, the function isn't called at all.
+ */
+static int raid10_mergeable_bvec(request_queue_t *q, struct bio *bio,
+ struct bio_vec *bio_vec)
+{
+ mddev_t *mddev = q->queuedata;
+ sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+ int max;
+ unsigned int chunk_sectors = mddev->chunk_size >> 9;
+ unsigned int bio_sectors = bio->bi_size >> 9;
+
+ max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
+ if (max < 0) max = 0; /* bio_add cannot handle a negative return */
+ if (max <= bio_vec->bv_len && bio_sectors == 0)
+ return bio_vec->bv_len;
+ else
+ return max;
+}
+
+/*
+ * This routine returns the disk from which the requested read should
+ * be done. There is a per-array 'next expected sequential IO' sector
+ * number - if this matches on the next IO then we use the last disk.
+ * There is also a per-disk 'last know head position' sector that is
+ * maintained from IRQ contexts, both the normal and the resync IO
+ * completion handlers update this position correctly. If there is no
+ * perfect sequential match then we pick the disk whose head is closest.
+ *
+ * If there are 2 mirrors in the same 2 devices, performance degrades
+ * because position is mirror, not device based.
+ *
+ * The rdev for the device selected will have nr_pending incremented.
+ */
+
+/*
+ * FIXME: possibly should rethink readbalancing and do it differently
+ * depending on near_copies / far_copies geometry.
+ */
+static int read_balance(conf_t *conf, r10bio_t *r10_bio)
+{
+ const unsigned long this_sector = r10_bio->sector;
+ int disk, slot, nslot;
+ const int sectors = r10_bio->sectors;
+ sector_t new_distance, current_distance;
+
+ raid10_find_phys(conf, r10_bio);
+ spin_lock_irq(&conf->device_lock);
+ /*
+ * Check if we can balance. We can balance on the whole
+ * device if no resync is going on, or below the resync window.
+ * We take the first readable disk when above the resync window.
+ */
+ if (conf->mddev->recovery_cp < MaxSector
+ && (this_sector + sectors >= conf->next_resync)) {
+ /* make sure that disk is operational */
+ slot = 0;
+ disk = r10_bio->devs[slot].devnum;
+
+ while (!conf->mirrors[disk].rdev ||
+ !conf->mirrors[disk].rdev->in_sync) {
+ slot++;
+ if (slot == conf->copies) {
+ slot = 0;
+ disk = -1;
+ break;
+ }
+ disk = r10_bio->devs[slot].devnum;
+ }
+ goto rb_out;
+ }
+
+
+ /* make sure the disk is operational */
+ slot = 0;
+ disk = r10_bio->devs[slot].devnum;
+ while (!conf->mirrors[disk].rdev ||
+ !conf->mirrors[disk].rdev->in_sync) {
+ slot ++;
+ if (slot == conf->copies) {
+ disk = -1;
+ goto rb_out;
+ }
+ disk = r10_bio->devs[slot].devnum;
+ }
+
+
+ current_distance = abs(this_sector - conf->mirrors[disk].head_position);
+
+ /* Find the disk whose head is closest */
+
+ for (nslot = slot; nslot < conf->copies; nslot++) {
+ int ndisk = r10_bio->devs[nslot].devnum;
+
+
+ if (!conf->mirrors[ndisk].rdev ||
+ !conf->mirrors[ndisk].rdev->in_sync)
+ continue;
+
+ if (!atomic_read(&conf->mirrors[ndisk].rdev->nr_pending)) {
+ disk = ndisk;
+ slot = nslot;
+ break;
+ }
+ new_distance = abs(r10_bio->devs[nslot].addr -
+ conf->mirrors[ndisk].head_position);
+ if (new_distance < current_distance) {
+ current_distance = new_distance;
+ disk = ndisk;
+ slot = nslot;
+ }
+ }
+
+rb_out:
+ r10_bio->read_slot = slot;
+/* conf->next_seq_sect = this_sector + sectors;*/
+
+ if (disk >= 0 && conf->mirrors[disk].rdev)
+ atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+ spin_unlock_irq(&conf->device_lock);
+
+ return disk;
+}
+
+static void unplug_slaves(mddev_t *mddev)
+{
+ conf_t *conf = mddev_to_conf(mddev);
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&conf->device_lock, flags);
+ for (i=0; i<mddev->raid_disks; i++) {
+ mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+ if (rdev && atomic_read(&rdev->nr_pending)) {
+ request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+
+ atomic_inc(&rdev->nr_pending);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+
+ if (r_queue->unplug_fn)
+ r_queue->unplug_fn(r_queue);
+
+ spin_lock_irqsave(&conf->device_lock, flags);
+ atomic_dec(&rdev->nr_pending);
+ }
+ }
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+}
+static void raid10_unplug(request_queue_t *q)
+{
+ unplug_slaves(q->queuedata);
+}
+
+static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
+ sector_t *error_sector)
+{
+ mddev_t *mddev = q->queuedata;
+ conf_t *conf = mddev_to_conf(mddev);
+ unsigned long flags;
+ int i, ret = 0;
+
+ spin_lock_irqsave(&conf->device_lock, flags);
+ for (i=0; i<mddev->raid_disks; i++) {
+ mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+ if (rdev && !rdev->faulty) {
+ struct block_device *bdev = rdev->bdev;
+ request_queue_t *r_queue = bdev_get_queue(bdev);
+
+ if (r_queue->issue_flush_fn) {
+ ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+ if (ret)
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ return ret;
+}
+
+/*
+ * Throttle resync depth, so that we can both get proper overlapping of
+ * requests, but are still able to handle normal requests quickly.
+ */
+#define RESYNC_DEPTH 32
+
+static void device_barrier(conf_t *conf, sector_t sect)
+{
+ spin_lock_irq(&conf->resync_lock);
+ wait_event_lock_irq(conf->wait_idle, !waitqueue_active(&conf->wait_resume),
+ conf->resync_lock, unplug_slaves(conf->mddev));
+
+ if (!conf->barrier++) {
+ wait_event_lock_irq(conf->wait_idle, !conf->nr_pending,
+ conf->resync_lock, unplug_slaves(conf->mddev));
+ if (conf->nr_pending)
+ BUG();
+ }
+ wait_event_lock_irq(conf->wait_resume, conf->barrier < RESYNC_DEPTH,
+ conf->resync_lock, unplug_slaves(conf->mddev));
+ conf->next_resync = sect;
+ spin_unlock_irq(&conf->resync_lock);
+}
+
+static int make_request(request_queue_t *q, struct bio * bio)
+{
+ mddev_t *mddev = q->queuedata;
+ conf_t *conf = mddev_to_conf(mddev);
+ mirror_info_t *mirror;
+ r10bio_t *r10_bio;
+ struct bio *read_bio;
+ int i;
+ int chunk_sects = conf->chunk_mask + 1;
+
+ /* If this request crosses a chunk boundary, we need to
+ * split it. This will only happen for 1 PAGE (or less) requests.
+ */
+ if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9)
+ > chunk_sects &&
+ conf->near_copies < conf->raid_disks)) {
+ struct bio_pair *bp;
+ /* Sanity check -- queue functions should prevent this happening */
+ if (bio->bi_vcnt != 1 ||
+ bio->bi_idx != 0)
+ goto bad_map;
+ /* This is a one page bio that upper layers
+ * refuse to split for us, so we need to split it.
+ */
+ bp = bio_split(bio, bio_split_pool,
+ chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
+ if (make_request(q, &bp->bio1))
+ generic_make_request(&bp->bio1);
+ if (make_request(q, &bp->bio2))
+ generic_make_request(&bp->bio2);
+
+ bio_pair_release(bp);
+ return 0;
+ bad_map:
+ printk("raid10_make_request bug: can't convert block across chunks"
+ " or bigger than %dk %llu %d\n", chunk_sects/2,
+ (unsigned long long)bio->bi_sector, bio->bi_size >> 10);
+
+ bio_io_error(bio, bio->bi_size);
+ return 0;
+ }
+
+ /*
+ * Register the new request and wait if the reconstruction
+ * thread has put up a bar for new requests.
+ * Continue immediately if no resync is active currently.
+ */
+ spin_lock_irq(&conf->resync_lock);
+ wait_event_lock_irq(conf->wait_resume, !conf->barrier, conf->resync_lock, );
+ conf->nr_pending++;
+ spin_unlock_irq(&conf->resync_lock);
+
+ if (bio_data_dir(bio)==WRITE) {
+ disk_stat_inc(mddev->gendisk, writes);
+ disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio));
+ } else {
+ disk_stat_inc(mddev->gendisk, reads);
+ disk_stat_add(mddev->gendisk, read_sectors, bio_sectors(bio));
+ }
+
+ r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+ r10_bio->master_bio = bio;
+ r10_bio->sectors = bio->bi_size >> 9;
+
+ r10_bio->mddev = mddev;
+ r10_bio->sector = bio->bi_sector;
+
+ if (bio_data_dir(bio) == READ) {
+ /*
+ * read balancing logic:
+ */
+ int disk = read_balance(conf, r10_bio);
+ int slot = r10_bio->read_slot;
+ if (disk < 0) {
+ raid_end_bio_io(r10_bio);
+ return 0;
+ }
+ mirror = conf->mirrors + disk;
+
+ read_bio = bio_clone(bio, GFP_NOIO);
+
+ r10_bio->devs[slot].bio = read_bio;
+
+ read_bio->bi_sector = r10_bio->devs[slot].addr +
+ mirror->rdev->data_offset;
+ read_bio->bi_bdev = mirror->rdev->bdev;
+ read_bio->bi_end_io = raid10_end_read_request;
+ read_bio->bi_rw = READ;
+ read_bio->bi_private = r10_bio;
+
+ generic_make_request(read_bio);
+ return 0;
+ }
+
+ /*
+ * WRITE:
+ */
+ /* first select target devices under spinlock and
+ * inc refcount on their rdev. Record them by setting
+ * bios[x] to bio
+ */
+ raid10_find_phys(conf, r10_bio);
+ spin_lock_irq(&conf->device_lock);
+ for (i = 0; i < conf->copies; i++) {
+ int d = r10_bio->devs[i].devnum;
+ if (conf->mirrors[d].rdev &&
+ !conf->mirrors[d].rdev->faulty) {
+ atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ r10_bio->devs[i].bio = bio;
+ } else
+ r10_bio->devs[i].bio = NULL;
+ }
+ spin_unlock_irq(&conf->device_lock);
+
+ atomic_set(&r10_bio->remaining, 1);
+ md_write_start(mddev);
+ for (i = 0; i < conf->copies; i++) {
+ struct bio *mbio;
+ int d = r10_bio->devs[i].devnum;
+ if (!r10_bio->devs[i].bio)
+ continue;
+
+ mbio = bio_clone(bio, GFP_NOIO);
+ r10_bio->devs[i].bio = mbio;
+
+ mbio->bi_sector = r10_bio->devs[i].addr+
+ conf->mirrors[d].rdev->data_offset;
+ mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
+ mbio->bi_end_io = raid10_end_write_request;
+ mbio->bi_rw = WRITE;
+ mbio->bi_private = r10_bio;
+
+ atomic_inc(&r10_bio->remaining);
+ generic_make_request(mbio);
+ }
+
+ if (atomic_dec_and_test(&r10_bio->remaining)) {
+ md_write_end(mddev);
+ raid_end_bio_io(r10_bio);
+ }
+
+ return 0;
+}
+
+static void status(struct seq_file *seq, mddev_t *mddev)
+{
+ conf_t *conf = mddev_to_conf(mddev);
+ int i;
+
+ if (conf->near_copies < conf->raid_disks)
+ seq_printf(seq, " %dK chunks", mddev->chunk_size/1024);
+ if (conf->near_copies > 1)
+ seq_printf(seq, " %d near-copies", conf->near_copies);
+ if (conf->far_copies > 1)
+ seq_printf(seq, " %d far-copies", conf->far_copies);
+
+ seq_printf(seq, " [%d/%d] [", conf->raid_disks,
+ conf->working_disks);
+ for (i = 0; i < conf->raid_disks; i++)
+ seq_printf(seq, "%s",
+ conf->mirrors[i].rdev &&
+ conf->mirrors[i].rdev->in_sync ? "U" : "_");
+ seq_printf(seq, "]");
+}
+
+static void error(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+ char b[BDEVNAME_SIZE];
+ conf_t *conf = mddev_to_conf(mddev);
+
+ /*
+ * If it is not operational, then we have already marked it as dead
+ * else if it is the last working disks, ignore the error, let the
+ * next level up know.
+ * else mark the drive as failed
+ */
+ if (rdev->in_sync
+ && conf->working_disks == 1)
+ /*
+ * Don't fail the drive, just return an IO error.
+ * The test should really be more sophisticated than
+ * "working_disks == 1", but it isn't critical, and
+ * can wait until we do more sophisticated "is the drive
+ * really dead" tests...
+ */
+ return;
+ if (rdev->in_sync) {
+ mddev->degraded++;
+ conf->working_disks--;
+ /*
+ * if recovery is running, make sure it aborts.
+ */
+ set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ }
+ rdev->in_sync = 0;
+ rdev->faulty = 1;
+ mddev->sb_dirty = 1;
+ printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
+ " Operation continuing on %d devices\n",
+ bdevname(rdev->bdev,b), conf->working_disks);
+}
+
+static void print_conf(conf_t *conf)
+{
+ int i;
+ mirror_info_t *tmp;
+
+ printk("RAID10 conf printout:\n");
+ if (!conf) {
+ printk("(!conf)\n");
+ return;
+ }
+ printk(" --- wd:%d rd:%d\n", conf->working_disks,
+ conf->raid_disks);
+
+ for (i = 0; i < conf->raid_disks; i++) {
+ char b[BDEVNAME_SIZE];
+ tmp = conf->mirrors + i;
+ if (tmp->rdev)
+ printk(" disk %d, wo:%d, o:%d, dev:%s\n",
+ i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+ bdevname(tmp->rdev->bdev,b));
+ }
+}
+
+static void close_sync(conf_t *conf)
+{
+ spin_lock_irq(&conf->resync_lock);
+ wait_event_lock_irq(conf->wait_resume, !conf->barrier,
+ conf->resync_lock, unplug_slaves(conf->mddev));
+ spin_unlock_irq(&conf->resync_lock);
+
+ if (conf->barrier) BUG();
+ if (waitqueue_active(&conf->wait_idle)) BUG();
+
+ mempool_destroy(conf->r10buf_pool);
+ conf->r10buf_pool = NULL;
+}
+
+static int raid10_spare_active(mddev_t *mddev)
+{
+ int i;
+ conf_t *conf = mddev->private;
+ mirror_info_t *tmp;
+
+ spin_lock_irq(&conf->device_lock);
+ /*
+ * Find all non-in_sync disks within the RAID10 configuration
+ * and mark them in_sync
+ */
+ for (i = 0; i < conf->raid_disks; i++) {
+ tmp = conf->mirrors + i;
+ if (tmp->rdev
+ && !tmp->rdev->faulty
+ && !tmp->rdev->in_sync) {
+ conf->working_disks++;
+ mddev->degraded--;
+ tmp->rdev->in_sync = 1;
+ }
+ }
+ spin_unlock_irq(&conf->device_lock);
+
+ print_conf(conf);
+ return 0;
+}
+
+
+static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+ conf_t *conf = mddev->private;
+ int found = 0;
+ int mirror;
+ mirror_info_t *p;
+
+ if (mddev->recovery_cp < MaxSector)
+ /* only hot-add to in-sync arrays, as recovery is
+ * very different from resync
+ */
+ return 0;
+ spin_lock_irq(&conf->device_lock);
+ for (mirror=0; mirror < mddev->raid_disks; mirror++)
+ if ( !(p=conf->mirrors+mirror)->rdev) {
+ p->rdev = rdev;
+
+ blk_queue_stack_limits(mddev->queue,
+ rdev->bdev->bd_disk->queue);
+ /* as we don't honour merge_bvec_fn, we must never risk
+ * violating it, so limit ->max_sector to one PAGE, as
+ * a one page request is never in violation.
+ */
+ if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
+ mddev->queue->max_sectors > (PAGE_SIZE>>9))
+ mddev->queue->max_sectors = (PAGE_SIZE>>9);
+
+ p->head_position = 0;
+ rdev->raid_disk = mirror;
+ found = 1;
+ break;
+ }
+ spin_unlock_irq(&conf->device_lock);
+
+ print_conf(conf);
+ return found;
+}
+
+static int raid10_remove_disk(mddev_t *mddev, int number)
+{
+ conf_t *conf = mddev->private;
+ int err = 1;
+ mirror_info_t *p = conf->mirrors+ number;
+
+ print_conf(conf);
+ spin_lock_irq(&conf->device_lock);
+ if (p->rdev) {
+ if (p->rdev->in_sync ||
+ atomic_read(&p->rdev->nr_pending)) {
+ err = -EBUSY;
+ goto abort;
+ }
+ p->rdev = NULL;
+ err = 0;
+ }
+ if (err)
+ MD_BUG();
+abort:
+ spin_unlock_irq(&conf->device_lock);
+
+ print_conf(conf);
+ return err;
+}
+
+
+static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+{
+ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+ conf_t *conf = mddev_to_conf(r10_bio->mddev);
+ int i,d;
+
+ if (bio->bi_size)
+ return 1;
+
+ for (i=0; i<conf->copies; i++)
+ if (r10_bio->devs[i].bio == bio)
+ break;
+ if (i == conf->copies)
+ BUG();
+ update_head_pos(i, r10_bio);
+ d = r10_bio->devs[i].devnum;
+ if (!uptodate)
+ md_error(r10_bio->mddev,
+ conf->mirrors[d].rdev);
+
+ /* for reconstruct, we always reschedule after a read.
+ * for resync, only after all reads
+ */
+ if (test_bit(R10BIO_IsRecover, &r10_bio->state) ||
+ atomic_dec_and_test(&r10_bio->remaining)) {
+ /* we have read all the blocks,
+ * do the comparison in process context in raid10d
+ */
+ reschedule_retry(r10_bio);
+ }
+ rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
+ return 0;
+}
+
+static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+{
+ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
+ mddev_t *mddev = r10_bio->mddev;
+ conf_t *conf = mddev_to_conf(mddev);
+ int i,d;
+
+ if (bio->bi_size)
+ return 1;
+
+ for (i = 0; i < conf->copies; i++)
+ if (r10_bio->devs[i].bio == bio)
+ break;
+ d = r10_bio->devs[i].devnum;
+
+ if (!uptodate)
+ md_error(mddev, conf->mirrors[d].rdev);
+ update_head_pos(i, r10_bio);
+
+ while (atomic_dec_and_test(&r10_bio->remaining)) {
+ if (r10_bio->master_bio == NULL) {
+ /* the primary of several recovery bios */
+ md_done_sync(mddev, r10_bio->sectors, 1);
+ put_buf(r10_bio);
+ break;
+ } else {
+ r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio;
+ put_buf(r10_bio);
+ r10_bio = r10_bio2;
+ }
+ }
+ rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+ return 0;
+}
+
+/*
+ * Note: sync and recover and handled very differently for raid10
+ * This code is for resync.
+ * For resync, we read through virtual addresses and read all blocks.
+ * If there is any error, we schedule a write. The lowest numbered
+ * drive is authoritative.
+ * However requests come for physical address, so we need to map.
+ * For every physical address there are raid_disks/copies virtual addresses,
+ * which is always are least one, but is not necessarly an integer.
+ * This means that a physical address can span multiple chunks, so we may
+ * have to submit multiple io requests for a single sync request.
+ */
+/*
+ * We check if all blocks are in-sync and only write to blocks that
+ * aren't in sync
+ */
+static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio)
+{
+ conf_t *conf = mddev_to_conf(mddev);
+ int i, first;
+ struct bio *tbio, *fbio;
+
+ atomic_set(&r10_bio->remaining, 1);
+
+ /* find the first device with a block */
+ for (i=0; i<conf->copies; i++)
+ if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags))
+ break;
+
+ if (i == conf->copies)
+ goto done;
+
+ first = i;
+ fbio = r10_bio->devs[i].bio;
+
+ /* now find blocks with errors */
+ for (i=first+1 ; i < conf->copies ; i++) {
+ int vcnt, j, d;
+
+ if (!test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags))
+ continue;
+ /* We know that the bi_io_vec layout is the same for
+ * both 'first' and 'i', so we just compare them.
+ * All vec entries are PAGE_SIZE;
+ */
+ tbio = r10_bio->devs[i].bio;
+ vcnt = r10_bio->sectors >> (PAGE_SHIFT-9);
+ for (j = 0; j < vcnt; j++)
+ if (memcmp(page_address(fbio->bi_io_vec[j].bv_page),
+ page_address(tbio->bi_io_vec[j].bv_page),
+ PAGE_SIZE))
+ break;
+ if (j == vcnt)
+ continue;
+ /* Ok, we need to write this bio
+ * First we need to fixup bv_offset, bv_len and
+ * bi_vecs, as the read request might have corrupted these
+ */
+ tbio->bi_vcnt = vcnt;
+ tbio->bi_size = r10_bio->sectors << 9;
+ tbio->bi_idx = 0;
+ tbio->bi_phys_segments = 0;
+ tbio->bi_hw_segments = 0;
+ tbio->bi_hw_front_size = 0;
+ tbio->bi_hw_back_size = 0;
+ tbio->bi_flags &= ~(BIO_POOL_MASK - 1);
+ tbio->bi_flags |= 1 << BIO_UPTODATE;
+ tbio->bi_next = NULL;
+ tbio->bi_rw = WRITE;
+ tbio->bi_private = r10_bio;
+ tbio->bi_sector = r10_bio->devs[i].addr;
+
+ for (j=0; j < vcnt ; j++) {
+ tbio->bi_io_vec[j].bv_offset = 0;
+ tbio->bi_io_vec[j].bv_len = PAGE_SIZE;
+
+ memcpy(page_address(tbio->bi_io_vec[j].bv_page),
+ page_address(fbio->bi_io_vec[j].bv_page),
+ PAGE_SIZE);
+ }
+ tbio->bi_end_io = end_sync_write;
+
+ d = r10_bio->devs[i].devnum;
+ atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ atomic_inc(&r10_bio->remaining);
+ md_sync_acct(conf->mirrors[d].rdev->bdev, tbio->bi_size >> 9);
+
+ generic_make_request(tbio);
+ }
+
+done:
+ if (atomic_dec_and_test(&r10_bio->remaining)) {
+ md_done_sync(mddev, r10_bio->sectors, 1);
+ put_buf(r10_bio);
+ }
+}
+
+/*
+ * Now for the recovery code.
+ * Recovery happens across physical sectors.
+ * We recover all non-is_sync drives by finding the virtual address of
+ * each, and then choose a working drive that also has that virt address.
+ * There is a separate r10_bio for each non-in_sync drive.
+ * Only the first two slots are in use. The first for reading,
+ * The second for writing.
+ *
+ */
+
+static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
+{
+ conf_t *conf = mddev_to_conf(mddev);
+ int i, d;
+ struct bio *bio, *wbio;
+
+
+ /* move the pages across to the second bio
+ * and submit the write request
+ */
+ bio = r10_bio->devs[0].bio;
+ wbio = r10_bio->devs[1].bio;
+ for (i=0; i < wbio->bi_vcnt; i++) {
+ struct page *p = bio->bi_io_vec[i].bv_page;
+ bio->bi_io_vec[i].bv_page = wbio->bi_io_vec[i].bv_page;
+ wbio->bi_io_vec[i].bv_page = p;
+ }
+ d = r10_bio->devs[1].devnum;
+
+ atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ md_sync_acct(conf->mirrors[d].rdev->bdev, wbio->bi_size >> 9);
+ generic_make_request(wbio);
+}
+
+
+/*
+ * This is a kernel thread which:
+ *
+ * 1. Retries failed read operations on working mirrors.
+ * 2. Updates the raid superblock when problems encounter.
+ * 3. Performs writes following reads for array syncronising.
+ */
+
+static void raid10d(mddev_t *mddev)
+{
+ r10bio_t *r10_bio;
+ struct bio *bio;
+ unsigned long flags;
+ conf_t *conf = mddev_to_conf(mddev);
+ struct list_head *head = &conf->retry_list;
+ int unplug=0;
+ mdk_rdev_t *rdev;
+
+ md_check_recovery(mddev);
+ md_handle_safemode(mddev);
+
+ for (;;) {
+ char b[BDEVNAME_SIZE];
+ spin_lock_irqsave(&conf->device_lock, flags);
+ if (list_empty(head))
+ break;
+ r10_bio = list_entry(head->prev, r10bio_t, retry_list);
+ list_del(head->prev);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+
+ mddev = r10_bio->mddev;
+ conf = mddev_to_conf(mddev);
+ if (test_bit(R10BIO_IsSync, &r10_bio->state)) {
+ sync_request_write(mddev, r10_bio);
+ unplug = 1;
+ } else if (test_bit(R10BIO_IsRecover, &r10_bio->state)) {
+ recovery_request_write(mddev, r10_bio);
+ unplug = 1;
+ } else {
+ int mirror;
+ bio = r10_bio->devs[r10_bio->read_slot].bio;
+ r10_bio->devs[r10_bio->read_slot].bio = NULL;
+ mirror = read_balance(conf, r10_bio);
+ r10_bio->devs[r10_bio->read_slot].bio = bio;
+ if (mirror == -1) {
+ printk(KERN_ALERT "raid10: %s: unrecoverable I/O"
+ " read error for block %llu\n",
+ bdevname(bio->bi_bdev,b),
+ (unsigned long long)r10_bio->sector);
+ raid_end_bio_io(r10_bio);
+ } else {
+ rdev = conf->mirrors[mirror].rdev;
+ if (printk_ratelimit())
+ printk(KERN_ERR "raid10: %s: redirecting sector %llu to"
+ " another mirror\n",
+ bdevname(rdev->bdev,b),
+ (unsigned long long)r10_bio->sector);
+ bio->bi_bdev = rdev->bdev;
+ bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr
+ + rdev->data_offset;
+ bio->bi_next = NULL;
+ bio->bi_flags &= (1<<BIO_CLONED);
+ bio->bi_flags |= 1 << BIO_UPTODATE;
+ bio->bi_idx = 0;
+ bio->bi_size = r10_bio->sectors << 9;
+ bio->bi_rw = READ;
+ unplug = 1;
+ generic_make_request(bio);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (unplug)
+ unplug_slaves(mddev);
+}
+
+
+static int init_resync(conf_t *conf)
+{
+ int buffs;
+
+ buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
+ if (conf->r10buf_pool)
+ BUG();
+ conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
+ if (!conf->r10buf_pool)
+ return -ENOMEM;
+ conf->next_resync = 0;
+ return 0;
+}
+
+/*
+ * perform a "sync" on one "block"
+ *
+ * We need to make sure that no normal I/O request - particularly write
+ * requests - conflict with active sync requests.
+ *
+ * This is achieved by tracking pending requests and a 'barrier' concept
+ * that can be installed to exclude normal IO requests.
+ *
+ * Resync and recovery are handled very differently.
+ * We differentiate by looking at MD_RECOVERY_SYNC in mddev->recovery.
+ *
+ * For resync, we iterate over virtual addresses, read all copies,
+ * and update if there are differences. If only one copy is live,
+ * skip it.
+ * For recovery, we iterate over physical addresses, read a good
+ * value for each non-in_sync drive, and over-write.
+ *
+ * So, for recovery we may have several outstanding complex requests for a
+ * given address, one for each out-of-sync device. We model this by allocating
+ * a number of r10_bio structures, one for each out-of-sync device.
+ * As we setup these structures, we collect all bio's together into a list
+ * which we then process collectively to add pages, and then process again
+ * to pass to generic_make_request.
+ *
+ * The r10_bio structures are linked using a borrowed master_bio pointer.
+ * This link is counted in ->remaining. When the r10_bio that points to NULL
+ * has its remaining count decremented to 0, the whole complex operation
+ * is complete.
+ *
+ */
+
+static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
+{
+ conf_t *conf = mddev_to_conf(mddev);
+ r10bio_t *r10_bio;
+ struct bio *biolist = NULL, *bio;
+ sector_t max_sector, nr_sectors;
+ int disk;
+ int i;
+
+ sector_t sectors_skipped = 0;
+ int chunks_skipped = 0;
+
+ if (!conf->r10buf_pool)
+ if (init_resync(conf))
+ return -ENOMEM;
+
+ skipped:
+ max_sector = mddev->size << 1;
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ max_sector = mddev->resync_max_sectors;
+ if (sector_nr >= max_sector) {
+ close_sync(conf);
+ return sectors_skipped;
+ }
+ if (chunks_skipped >= conf->raid_disks) {
+ /* if there has been nothing to do on any drive,
+ * then there is nothing to do at all..
+ */
+ sector_t sec = max_sector - sector_nr;
+ md_done_sync(mddev, sec, 1);
+ return sec + sectors_skipped;
+ }
+
+ /* make sure whole request will fit in a chunk - if chunks
+ * are meaningful
+ */
+ if (conf->near_copies < conf->raid_disks &&
+ max_sector > (sector_nr | conf->chunk_mask))
+ max_sector = (sector_nr | conf->chunk_mask) + 1;
+ /*
+ * If there is non-resync activity waiting for us then
+ * put in a delay to throttle resync.
+ */
+ if (!go_faster && waitqueue_active(&conf->wait_resume))
+ schedule_timeout(HZ);
+ device_barrier(conf, sector_nr + RESYNC_SECTORS);
+
+ /* Again, very different code for resync and recovery.
+ * Both must result in an r10bio with a list of bios that
+ * have bi_end_io, bi_sector, bi_bdev set,
+ * and bi_private set to the r10bio.
+ * For recovery, we may actually create several r10bios
+ * with 2 bios in each, that correspond to the bios in the main one.
+ * In this case, the subordinate r10bios link back through a
+ * borrowed master_bio pointer, and the counter in the master
+ * includes a ref from each subordinate.
+ */
+ /* First, we decide what to do and set ->bi_end_io
+ * To end_sync_read if we want to read, and
+ * end_sync_write if we will want to write.
+ */
+
+ if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+ /* recovery... the complicated one */
+ int i, j, k;
+ r10_bio = NULL;
+
+ for (i=0 ; i<conf->raid_disks; i++)
+ if (conf->mirrors[i].rdev &&
+ !conf->mirrors[i].rdev->in_sync) {
+ /* want to reconstruct this device */
+ r10bio_t *rb2 = r10_bio;
+
+ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+ spin_lock_irq(&conf->resync_lock);
+ conf->nr_pending++;
+ if (rb2) conf->barrier++;
+ spin_unlock_irq(&conf->resync_lock);
+ atomic_set(&r10_bio->remaining, 0);
+
+ r10_bio->master_bio = (struct bio*)rb2;
+ if (rb2)
+ atomic_inc(&rb2->remaining);
+ r10_bio->mddev = mddev;
+ set_bit(R10BIO_IsRecover, &r10_bio->state);
+ r10_bio->sector = raid10_find_virt(conf, sector_nr, i);
+ raid10_find_phys(conf, r10_bio);
+ for (j=0; j<conf->copies;j++) {
+ int d = r10_bio->devs[j].devnum;
+ if (conf->mirrors[d].rdev &&
+ conf->mirrors[d].rdev->in_sync) {
+ /* This is where we read from */
+ bio = r10_bio->devs[0].bio;
+ bio->bi_next = biolist;
+ biolist = bio;
+ bio->bi_private = r10_bio;
+ bio->bi_end_io = end_sync_read;
+ bio->bi_rw = 0;
+ bio->bi_sector = r10_bio->devs[j].addr +
+ conf->mirrors[d].rdev->data_offset;
+ bio->bi_bdev = conf->mirrors[d].rdev->bdev;
+ atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ atomic_inc(&r10_bio->remaining);
+ /* and we write to 'i' */
+
+ for (k=0; k<conf->copies; k++)
+ if (r10_bio->devs[k].devnum == i)
+ break;
+ bio = r10_bio->devs[1].bio;
+ bio->bi_next = biolist;
+ biolist = bio;
+ bio->bi_private = r10_bio;
+ bio->bi_end_io = end_sync_write;
+ bio->bi_rw = 1;
+ bio->bi_sector = r10_bio->devs[k].addr +
+ conf->mirrors[i].rdev->data_offset;
+ bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+
+ r10_bio->devs[0].devnum = d;
+ r10_bio->devs[1].devnum = i;
+
+ break;
+ }
+ }
+ if (j == conf->copies) {
+ BUG();
+ }
+ }
+ if (biolist == NULL) {
+ while (r10_bio) {
+ r10bio_t *rb2 = r10_bio;
+ r10_bio = (r10bio_t*) rb2->master_bio;
+ rb2->master_bio = NULL;
+ put_buf(rb2);
+ }
+ goto giveup;
+ }
+ } else {
+ /* resync. Schedule a read for every block at this virt offset */
+ int count = 0;
+ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+
+ spin_lock_irq(&conf->resync_lock);
+ conf->nr_pending++;
+ spin_unlock_irq(&conf->resync_lock);
+
+ r10_bio->mddev = mddev;
+ atomic_set(&r10_bio->remaining, 0);
+
+ r10_bio->master_bio = NULL;
+ r10_bio->sector = sector_nr;
+ set_bit(R10BIO_IsSync, &r10_bio->state);
+ raid10_find_phys(conf, r10_bio);
+ r10_bio->sectors = (sector_nr | conf->chunk_mask) - sector_nr +1;
+ spin_lock_irq(&conf->device_lock);
+ for (i=0; i<conf->copies; i++) {
+ int d = r10_bio->devs[i].devnum;
+ bio = r10_bio->devs[i].bio;
+ bio->bi_end_io = NULL;
+ if (conf->mirrors[d].rdev == NULL ||
+ conf->mirrors[d].rdev->faulty)
+ continue;
+ atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ atomic_inc(&r10_bio->remaining);
+ bio->bi_next = biolist;
+ biolist = bio;
+ bio->bi_private = r10_bio;
+ bio->bi_end_io = end_sync_read;
+ bio->bi_rw = 0;
+ bio->bi_sector = r10_bio->devs[i].addr +
+ conf->mirrors[d].rdev->data_offset;
+ bio->bi_bdev = conf->mirrors[d].rdev->bdev;
+ count++;
+ }
+ spin_unlock_irq(&conf->device_lock);
+ if (count < 2) {
+ for (i=0; i<conf->copies; i++) {
+ int d = r10_bio->devs[i].devnum;
+ if (r10_bio->devs[i].bio->bi_end_io)
+ atomic_dec(&conf->mirrors[d].rdev->nr_pending);
+ }
+ put_buf(r10_bio);
+ goto giveup;
+ }
+ }
+
+ for (bio = biolist; bio ; bio=bio->bi_next) {
+
+ bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+ if (bio->bi_end_io)
+ bio->bi_flags |= 1 << BIO_UPTODATE;
+ bio->bi_vcnt = 0;
+ bio->bi_idx = 0;
+ bio->bi_phys_segments = 0;
+ bio->bi_hw_segments = 0;
+ bio->bi_size = 0;
+ }
+
+ nr_sectors = 0;
+ do {
+ struct page *page;
+ int len = PAGE_SIZE;
+ disk = 0;
+ if (sector_nr + (len>>9) > max_sector)
+ len = (max_sector - sector_nr) << 9;
+ if (len == 0)
+ break;
+ for (bio= biolist ; bio ; bio=bio->bi_next) {
+ page = bio->bi_io_vec[bio->bi_vcnt].bv_page;
+ if (bio_add_page(bio, page, len, 0) == 0) {
+ /* stop here */
+ struct bio *bio2;
+ bio->bi_io_vec[bio->bi_vcnt].bv_page = page;
+ for (bio2 = biolist; bio2 && bio2 != bio; bio2 = bio2->bi_next) {
+ /* remove last page from this bio */
+ bio2->bi_vcnt--;
+ bio2->bi_size -= len;
+ bio2->bi_flags &= ~(1<< BIO_SEG_VALID);
+ }
+ goto bio_full;
+ }
+ disk = i;
+ }
+ nr_sectors += len>>9;
+ sector_nr += len>>9;
+ } while (biolist->bi_vcnt < RESYNC_PAGES);
+ bio_full:
+ r10_bio->sectors = nr_sectors;
+
+ while (biolist) {
+ bio = biolist;
+ biolist = biolist->bi_next;
+
+ bio->bi_next = NULL;
+ r10_bio = bio->bi_private;
+ r10_bio->sectors = nr_sectors;
+
+ if (bio->bi_end_io == end_sync_read) {
+ md_sync_acct(bio->bi_bdev, nr_sectors);
+ generic_make_request(bio);
+ }
+ }
+
+ return nr_sectors;
+ giveup:
+ /* There is nowhere to write, so all non-sync
+ * drives must be failed, so try the next chunk...
+ */
+ {
+ int sec = max_sector - sector_nr;
+ sectors_skipped += sec;
+ chunks_skipped ++;
+ sector_nr = max_sector;
+ md_done_sync(mddev, sec, 1);
+ goto skipped;
+ }
+}
+
+static int run(mddev_t *mddev)
+{
+ conf_t *conf;
+ int i, disk_idx;
+ mirror_info_t *disk;
+ mdk_rdev_t *rdev;
+ struct list_head *tmp;
+ int nc, fc;
+ sector_t stride, size;
+
+ if (mddev->level != 10) {
+ printk(KERN_ERR "raid10: %s: raid level not set correctly... (%d)\n",
+ mdname(mddev), mddev->level);
+ goto out;
+ }
+ nc = mddev->layout & 255;
+ fc = (mddev->layout >> 8) & 255;
+ if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
+ (mddev->layout >> 16)) {
+ printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n",
+ mdname(mddev), mddev->layout);
+ goto out;
+ }
+ /*
+ * copy the already verified devices into our private RAID10
+ * bookkeeping area. [whatever we allocate in run(),
+ * should be freed in stop()]
+ */
+ conf = kmalloc(sizeof(conf_t), GFP_KERNEL);
+ mddev->private = conf;
+ if (!conf) {
+ printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
+ mdname(mddev));
+ goto out;
+ }
+ memset(conf, 0, sizeof(*conf));
+ conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+ GFP_KERNEL);
+ if (!conf->mirrors) {
+ printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
+ mdname(mddev));
+ goto out_free_conf;
+ }
+ memset(conf->mirrors, 0, sizeof(struct mirror_info)*mddev->raid_disks);
+
+ conf->near_copies = nc;
+ conf->far_copies = fc;
+ conf->copies = nc*fc;
+ conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
+ conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
+ stride = mddev->size >> (conf->chunk_shift-1);
+ sector_div(stride, fc);
+ conf->stride = stride << conf->chunk_shift;
+
+ conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
+ r10bio_pool_free, conf);
+ if (!conf->r10bio_pool) {
+ printk(KERN_ERR "raid10: couldn't allocate memory for %s\n",
+ mdname(mddev));
+ goto out_free_conf;
+ }
+ mddev->queue->unplug_fn = raid10_unplug;
+
+ mddev->queue->issue_flush_fn = raid10_issue_flush;
+
+ ITERATE_RDEV(mddev, rdev, tmp) {
+ disk_idx = rdev->raid_disk;
+ if (disk_idx >= mddev->raid_disks
+ || disk_idx < 0)
+ continue;
+ disk = conf->mirrors + disk_idx;
+
+ disk->rdev = rdev;
+
+ blk_queue_stack_limits(mddev->queue,
+ rdev->bdev->bd_disk->queue);
+ /* as we don't honour merge_bvec_fn, we must never risk
+ * violating it, so limit ->max_sector to one PAGE, as
+ * a one page request is never in violation.
+ */
+ if (rdev->bdev->bd_disk->queue->merge_bvec_fn &&
+ mddev->queue->max_sectors > (PAGE_SIZE>>9))
+ mddev->queue->max_sectors = (PAGE_SIZE>>9);
+
+ disk->head_position = 0;
+ if (!rdev->faulty && rdev->in_sync)
+ conf->working_disks++;
+ }
+ conf->raid_disks = mddev->raid_disks;
+ conf->mddev = mddev;
+ conf->device_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&conf->retry_list);
+
+ conf->resync_lock = SPIN_LOCK_UNLOCKED;
+ init_waitqueue_head(&conf->wait_idle);
+ init_waitqueue_head(&conf->wait_resume);
+
+ if (!conf->working_disks) {
+ printk(KERN_ERR "raid10: no operational mirrors for %s\n",
+ mdname(mddev));
+ goto out_free_conf;
+ }
+
+ mddev->degraded = 0;
+ for (i = 0; i < conf->raid_disks; i++) {
+
+ disk = conf->mirrors + i;
+
+ if (!disk->rdev) {
+ disk->head_position = 0;
+ mddev->degraded++;
+ }
+ }
+
+
+ mddev->thread = md_register_thread(raid10d, mddev, "%s_raid10");
+ if (!mddev->thread) {
+ printk(KERN_ERR
+ "raid10: couldn't allocate thread for %s\n",
+ mdname(mddev));
+ goto out_free_conf;
+ }
+
+ printk(KERN_INFO
+ "raid10: raid set %s active with %d out of %d devices\n",
+ mdname(mddev), mddev->raid_disks - mddev->degraded,
+ mddev->raid_disks);
+ /*
+ * Ok, everything is just fine now
+ */
+ size = conf->stride * conf->raid_disks;
+ sector_div(size, conf->near_copies);
+ mddev->array_size = size/2;
+ mddev->resync_max_sectors = size;
+
+ /* Calculate max read-ahead size.
+ * We need to readahead at least twice a whole stripe....
+ * maybe...
+ */
+ {
+ int stripe = conf->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE;
+ stripe /= conf->near_copies;
+ if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
+ mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+ }
+
+ if (conf->near_copies < mddev->raid_disks)
+ blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
+ return 0;
+
+out_free_conf:
+ if (conf->r10bio_pool)
+ mempool_destroy(conf->r10bio_pool);
+ if (conf->mirrors)
+ kfree(conf->mirrors);
+ kfree(conf);
+ mddev->private = NULL;
+out:
+ return -EIO;
+}
+
+static int stop(mddev_t *mddev)
+{
+ conf_t *conf = mddev_to_conf(mddev);
+
+ md_unregister_thread(mddev->thread);
+ mddev->thread = NULL;
+ if (conf->r10bio_pool)
+ mempool_destroy(conf->r10bio_pool);
+ if (conf->mirrors)
+ kfree(conf->mirrors);
+ kfree(conf);
+ mddev->private = NULL;
+ return 0;
+}
+
+
+static mdk_personality_t raid10_personality =
+{
+ .name = "raid10",
+ .owner = THIS_MODULE,
+ .make_request = make_request,
+ .run = run,
+ .stop = stop,
+ .status = status,
+ .error_handler = error,
+ .hot_add_disk = raid10_add_disk,
+ .hot_remove_disk= raid10_remove_disk,
+ .spare_active = raid10_spare_active,
+ .sync_request = sync_request,
+};
+
+static int __init raid_init(void)
+{
+ return register_md_personality(RAID10, &raid10_personality);
+}
+
+static void raid_exit(void)
+{
+ unregister_md_personality(RAID10);
+}
+
+module_init(raid_init);
+module_exit(raid_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("md-personality-9"); /* RAID10 */
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index df2d07c66ed31..104734ca25ba3 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1071,7 +1071,8 @@ static void handle_stripe(struct stripe_head *sh)
PRINTK("Reading block %d (sync=%d)\n",
i, syncing);
if (syncing)
- md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS);
+ md_sync_acct(conf->disks[i].rdev->bdev,
+ STRIPE_SECTORS);
}
}
}
@@ -1256,7 +1257,7 @@ static void handle_stripe(struct stripe_head *sh)
if (rdev) {
if (test_bit(R5_Syncio, &sh->dev[i].flags))
- md_sync_acct(rdev, STRIPE_SECTORS);
+ md_sync_acct(rdev->bdev, STRIPE_SECTORS);
bi->bi_bdev = rdev->bdev;
PRINTK("for %llu schedule op %ld on disc %d\n",
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index 57dcc2b00807e..e5f711b2797f8 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -1208,7 +1208,8 @@ static void handle_stripe(struct stripe_head *sh)
PRINTK("Reading block %d (sync=%d)\n",
i, syncing);
if (syncing)
- md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS);
+ md_sync_acct(conf->disks[i].rdev->bdev,
+ STRIPE_SECTORS);
}
}
}
@@ -1418,7 +1419,7 @@ static void handle_stripe(struct stripe_head *sh)
if (rdev) {
if (test_bit(R5_Syncio, &sh->dev[i].flags))
- md_sync_acct(rdev, STRIPE_SECTORS);
+ md_sync_acct(rdev->bdev, STRIPE_SECTORS);
bi->bi_bdev = rdev->bdev;
PRINTK("for %llu schedule op %ld on disc %d\n",
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index a4c3794a185cc..90581534f1af8 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1196,7 +1196,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf
int status;
char fragbuf[HOST_LINK_BUF_SIZE];
int fragpos = 0;
- int fraglen;
+ size_t fraglen;
unsigned long timeout;
int written;
@@ -1257,7 +1257,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* resu
int slot;
int slot_count = 0;
int idx;
- int fraglen;
+ size_t fraglen;
int connection_id = -1;
int found = 0;
u8 hdr[2];
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index dfa5be4e2be2d..df42f82bec3cf 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -563,7 +563,7 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
if (buffer2 != 0)
printk(KERN_WARNING "buffer2 not 0: %p.\n", buffer2);
if (buffer1_len > 32768)
- printk(KERN_WARNING "length > 32k: %u.\n", buffer1_len);
+ printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
/* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
buffer1_len, buffer1_len / TS_SZ, buffer1); */
dvb_net_ule(dev, buffer1, buffer1_len);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 99647b5ffd2be..a5ff5ec02b155 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -1,6 +1,6 @@
config DVB_AV7110
tristate "AV7110 cards"
- depends on DVB_CORE
+ depends on DVB_CORE && PCI
select FW_LOADER
select VIDEO_DEV
select VIDEO_SAA7146_VV
@@ -45,7 +45,7 @@ config DVB_AV7110_OSD
config DVB_BUDGET
tristate "Budget cards"
- depends on DVB_CORE
+ depends on DVB_CORE && PCI
select VIDEO_SAA7146
help
Support for simple SAA7146 based DVB cards
@@ -59,7 +59,7 @@ config DVB_BUDGET
config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
- depends on DVB_CORE
+ depends on DVB_CORE && PCI
select VIDEO_SAA7146
help
Support for simple SAA7146 based DVB cards
@@ -76,7 +76,7 @@ config DVB_BUDGET_CI
config DVB_BUDGET_AV
tristate "Budget cards with analog video inputs"
- depends on DVB_CORE
+ depends on DVB_CORE && PCI
select VIDEO_DEV
select VIDEO_SAA7146_VV
help
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 5e3f5eacc7767..cc48a65e8b143 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1181,7 +1181,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
firmware_size = fw_entry->size;
if (firmware_size < 60) {
- printk("%s: firmware size too small for DSP code (%u < 60).\n",
+ printk("%s: firmware size too small for DSP code (%zu < 60).\n",
__FUNCTION__, firmware_size);
return -1;
}
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 6f3fe234e2d3c..a586b1bc93fab 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -58,7 +58,7 @@ static int video_nr = -1;
static inline void meye_initq(struct meye_queue *queue) {
queue->head = queue->tail = 0;
queue->len = 0;
- queue->s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
+ queue->s_lock = SPIN_LOCK_UNLOCKED;
init_waitqueue_head(&queue->proc_list);
}
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 75c07f89e47e6..f51a3e50f7ece 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -2416,7 +2416,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
}
} else {
printk(MYIOC_s_ERR_FMT
- "Invalid IOC facts reply, msgLength=%d offsetof=%d!\n",
+ "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
RequestFrameSize)/sizeof(u32)));
return -66;
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index ee29ced8784bd..9dcf33c2aea1f 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -62,10 +62,17 @@ static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_
int result = -ENOMEM;
struct service_processor *sp;
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "%s: can't enable PCI device at %s\n",
+ DRIVER_NAME, pci_name(pdev));
+ return -ENODEV;
+ }
+
sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
if (sp == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory\n");
- return result;
+ result = -ENOMEM;
+ goto error_kmalloc;
}
memset(sp, 0, sizeof(struct service_processor));
@@ -148,6 +155,8 @@ error_heartbeat:
ibmasm_event_buffer_exit(sp);
error_eventbuffer:
kfree(sp);
+error_kmalloc:
+ pci_disable_device(pdev);
return result;
}
@@ -166,6 +175,7 @@ static void __exit ibmasm_remove_one(struct pci_dev *pdev)
iounmap(sp->base_address);
ibmasm_event_buffer_exit(sp);
kfree(sp);
+ pci_disable_device(pdev);
}
static struct pci_device_id ibmasm_pci_table[] =
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index daf554c003cab..b6ae9482443a7 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -29,6 +29,7 @@
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_ATMEL 0x001f
#define MANUFACTURER_FUJITSU 0x0004
+#define MANUFACTURER_HYUNDAI 0x00AD
#define MANUFACTURER_INTEL 0x0089
#define MANUFACTURER_MACRONIX 0x00C2
#define MANUFACTURER_PMC 0x009D
@@ -56,6 +57,7 @@
#define AM29F040 0x00A4
#define AM29LV040B 0x004F
#define AM29F032B 0x0041
+#define AM29F002T 0x00B0
/* Atmel */
#define AT49BV512 0x0003
@@ -77,6 +79,8 @@
#define MBM29LV400TC 0x22B9
#define MBM29LV400BC 0x22BA
+/* Hyundai */
+#define HY29F002T 0x00B0
/* Intel */
#define I28F004B3T 0x00d4
@@ -106,6 +110,7 @@
#define MX29LV160T 0x22C4
#define MX29LV160B 0x2249
#define MX29F016 0x00AD
+#define MX29F002T 0x00B0
#define MX29F004T 0x0045
#define MX29F004B 0x0046
@@ -507,6 +512,17 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x10000,8),
}
}, {
+ mfr_id: MANUFACTURER_AMD,
+ dev_id: AM29F002T,
+ name: "AMD AM29F002T",
+ DevSize: SIZE_256KiB,
+ NumEraseRegions: 4,
+ regions: {ERASEINFO(0x10000,3),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1)
+ }
+ }, {
.mfr_id = MANUFACTURER_ATMEL,
.dev_id = AT49BV512,
.name = "Atmel AT49BV512",
@@ -752,6 +768,17 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x04000,1)
}
}, {
+ mfr_id: MANUFACTURER_HYUNDAI,
+ dev_id: HY29F002T,
+ name: "Hyundai HY29F002T",
+ DevSize: SIZE_256KiB,
+ NumEraseRegions: 4,
+ regions: {ERASEINFO(0x10000,3),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1)
+ }
+ }, {
.mfr_id = MANUFACTURER_INTEL,
.dev_id = I28F004B3B,
.name = "Intel 28F004B3B",
@@ -1135,6 +1162,17 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x10000,7),
}
}, {
+ mfr_id: MANUFACTURER_MACRONIX,
+ dev_id: MX29F002T,
+ name: "Macronix MX29F002T",
+ DevSize: SIZE_256KiB,
+ NumEraseRegions: 4,
+ regions: {ERASEINFO(0x10000,3),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1)
+ }
+ }, {
.mfr_id = MANUFACTURER_PMC,
.dev_id = PM49FL002,
.name = "PMC Pm49FL002",
@@ -1570,7 +1608,7 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x02000, 2),
ERASEINFO(0x04000, 1),
}
- }
+ }
};
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
index 842f1b0465bb2..b7fd849dc1fc2 100644
--- a/drivers/mtd/maps/edb7312.c
+++ b/drivers/mtd/maps/edb7312.c
@@ -71,14 +71,14 @@ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
#endif
-static int mtd_parts_nb = 0;
-static struct mtd_partition *mtd_parts = 0;
+static int mtd_parts_nb;
+static struct mtd_partition *mtd_parts;
int __init init_edb7312nor(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
- const char *part_type = 0;
+ const char *part_type = NULL;
printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
WINDOW_SIZE, WINDOW_ADDR);
@@ -92,7 +92,7 @@ int __init init_edb7312nor(void)
simple_map_init(&edb7312nor_map);
- mymtd = 0;
+ mymtd = NULL;
type = rom_probe_types;
for(; !mymtd && *type; type++) {
mymtd = do_map_probe(*type, &edb7312nor_map);
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
index a05fc01b93672..7d2b42436958a 100644
--- a/drivers/mtd/maps/impa7.c
+++ b/drivers/mtd/maps/impa7.c
@@ -77,7 +77,7 @@ int __init init_impa7(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
- const char *part_type = 0;
+ const char *part_type = NULL;
int i;
static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
{ WINDOW_ADDR0, WINDOW_SIZE0 },
@@ -99,7 +99,7 @@ int __init init_impa7(void)
}
simple_map_init(&impa7_map[i]);
- impa7_mtd[i] = 0;
+ impa7_mtd[i] = NULL;
type = rom_probe_types;
for(; !impa7_mtd[i] && *type; type++) {
impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index a8a4e1ac843e9..eee7faa5cf110 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -269,7 +269,8 @@ static int memcmpb(void *a, int c, int n)
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
int check_oob)
{
- int i, retlen;
+ int i;
+ size_t retlen;
u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
for (i = 0; i < len; i += SECTORSIZE) {
@@ -366,7 +367,8 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
{
unsigned int block, i, status;
struct nftl_bci bci;
- int sectors_per_block, retlen;
+ int sectors_per_block;
+ size_t retlen;
sectors_per_block = nftl->EraseSize / SECTORSIZE;
block = first_block;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index e62be9137b231..2a94719a4226a 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -593,6 +593,7 @@ struct rtl8139_private {
int time_to_die;
struct mii_if_info mii;
unsigned int regs_len;
+ unsigned long fifo_copy_timeout;
};
MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
@@ -1927,6 +1928,24 @@ static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,
}
#endif
+static void rtl8139_isr_ack(struct rtl8139_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ u16 status;
+
+ status = RTL_R16 (IntrStatus) & RxAckBits;
+
+ /* Clear out errors and receive interrupts */
+ if (likely(status != 0)) {
+ if (unlikely(status & (RxFIFOOver | RxOverflow))) {
+ tp->stats.rx_errors++;
+ if (status & RxFIFOOver)
+ tp->stats.rx_fifo_errors++;
+ }
+ RTL_W16_F (IntrStatus, RxAckBits);
+ }
+}
+
static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
int budget)
{
@@ -1934,9 +1953,10 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
int received = 0;
unsigned char *rx_ring = tp->rx_ring;
unsigned int cur_rx = tp->cur_rx;
+ unsigned int rx_size = 0;
DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
RTL_R16 (RxBufAddr),
RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
@@ -1944,10 +1964,8 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
&& (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
u32 ring_offset = cur_rx % RX_BUF_LEN;
u32 rx_status;
- unsigned int rx_size;
unsigned int pkt_size;
struct sk_buff *skb;
- u16 status;
rmb();
@@ -1976,10 +1994,24 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
* since EarlyRx is disabled.
*/
if (unlikely(rx_size == 0xfff0)) {
+ if (!tp->fifo_copy_timeout)
+ tp->fifo_copy_timeout = jiffies + 2;
+ else if (time_after(jiffies, tp->fifo_copy_timeout)) {
+ DPRINTK ("%s: hung FIFO. Reset.", dev->name);
+ rx_size = 0;
+ goto no_early_rx;
+ }
+ if (netif_msg_intr(tp)) {
+ printk(KERN_DEBUG "%s: fifo copy in progress.",
+ dev->name);
+ }
tp->xstats.early_rx++;
- goto done;
+ break;
}
+no_early_rx:
+ tp->fifo_copy_timeout = 0;
+
/* If Rx err or invalid rx_size/rx_status received
* (which happens if we get lost in the ring),
* Rx process gets reset, so we abort any further
@@ -1989,7 +2021,8 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
(rx_size < 8) ||
(!(rx_status & RxStatusOK)))) {
rtl8139_rx_err (rx_status, dev, tp, ioaddr);
- return -1;
+ received = -1;
+ goto out;
}
/* Malloc up new buffer, compatible with net-2e. */
@@ -2025,19 +2058,11 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));
- /* Clear out errors and receive interrupts */
- status = RTL_R16 (IntrStatus) & RxAckBits;
- if (likely(status != 0)) {
- if (unlikely(status & (RxFIFOOver | RxOverflow))) {
- tp->stats.rx_errors++;
- if (status & RxFIFOOver)
- tp->stats.rx_fifo_errors++;
- }
- RTL_W16_F (IntrStatus, RxAckBits);
- }
+ rtl8139_isr_ack(tp);
}
- done:
+ if (unlikely(!received || rx_size == 0xfff0))
+ rtl8139_isr_ack(tp);
#if RTL8139_DEBUG > 1
DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
@@ -2047,6 +2072,15 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
#endif
tp->cur_rx = cur_rx;
+
+ /*
+ * The receive buffer should be mostly empty.
+ * Tell NAPI to reenable the Rx irq.
+ */
+ if (tp->fifo_copy_timeout)
+ received = budget;
+
+out:
return received;
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index edfd11763ee59..ef7d7d512455f 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1752,7 +1752,7 @@ config VIA_VELOCITY
If you have a VIA "Velocity" based network card say Y here.
To compile this driver as a module, choose M here. The module
- will be called via-rhine.
+ will be called via-velocity.
config LAN_SAA9730
bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)"
@@ -2046,8 +2046,20 @@ config R8169
config R8169_NAPI
bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
- depends on R8169 && EXPERIMENTAL
+ depends on R8169 && EXPERIMENTAL
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
config SK98LIN
tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 86302faf947bb..d463673925956 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -92,7 +92,7 @@ enum dl2x_offsets {
EepromCtrl = 0x4a,
ExpromAddr = 0x4c,
Exprodata = 0x50,
- WakeEvent0x51,
+ WakeEvent = 0x51,
CountDown = 0x54,
IntStatusAck = 0x5a,
IntEnable = 0x5c,
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 4e4b3db4e00e0..34f19a79c2d7f 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -128,8 +128,8 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
static int e1000_set_mac(struct net_device *netdev, void *p);
-static inline void e1000_irq_disable(struct e1000_adapter *adapter);
-static inline void e1000_irq_enable(struct e1000_adapter *adapter);
+static void e1000_irq_disable(struct e1000_adapter *adapter);
+static void e1000_irq_enable(struct e1000_adapter *adapter);
static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
#ifdef CONFIG_E1000_NAPI
@@ -146,9 +146,9 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
void set_ethtool_ops(struct net_device *netdev);
static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
-static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
- struct e1000_rx_desc *rx_desc,
- struct sk_buff *skb);
+static void e1000_rx_checksum(struct e1000_adapter *adapter,
+ struct e1000_rx_desc *rx_desc,
+ struct sk_buff *skb);
static void e1000_tx_timeout(struct net_device *dev);
static void e1000_tx_timeout_task(struct net_device *dev);
static void e1000_smartspeed(struct e1000_adapter *adapter);
@@ -2077,7 +2077,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
* @adapter: board private structure
**/
-static inline void
+static void
e1000_irq_disable(struct e1000_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
@@ -2091,7 +2091,7 @@ e1000_irq_disable(struct e1000_adapter *adapter)
* @adapter: board private structure
**/
-static inline void
+static void
e1000_irq_enable(struct e1000_adapter *adapter)
{
if(likely(atomic_dec_and_test(&adapter->irq_sem))) {
@@ -2593,7 +2593,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
* @sk_buff: socket buffer with received data
**/
-static inline void
+static void
e1000_rx_checksum(struct e1000_adapter *adapter,
struct e1000_rx_desc *rx_desc,
struct sk_buff *skb)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 03388203e566f..a8ceee273e3bd 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -307,8 +307,8 @@ static int gfar_probe(struct ocp_device *ocpdev)
/* Print out the device info */
printk(KERN_INFO DEVICE_NAME, dev->name);
for (idx = 0; idx < 6; idx++)
- printk(KERN_INFO "%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
- printk(KERN_INFO "\n");
+ printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
+ printk("\n");
/* Even more device info helps when determining which kernel */
/* provided which set of benchmarks. Since this is global for all */
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index b5169e8492c42..6b0cb2cabdc69 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -559,7 +559,7 @@ static void hamachi_tx_timeout(struct net_device *dev);
static void hamachi_init_ring(struct net_device *dev);
static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static inline int hamachi_rx(struct net_device *dev);
+static int hamachi_rx(struct net_device *dev);
static inline int hamachi_tx(struct net_device *dev);
static void hamachi_error(struct net_device *dev, int intr_status);
static int hamachi_close(struct net_device *dev);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 9f3dac7d26e50..4beb7ac2a8618 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -246,8 +246,14 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *scc_get_stats(struct net_device *dev);
static int scc_set_mac_address(struct net_device *dev, void *sa);
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static inline void tx_on(struct scc_priv *priv);
+static inline void rx_on(struct scc_priv *priv);
+static inline void rx_off(struct scc_priv *priv);
+static void start_timer(struct scc_priv *priv, int t, int r15);
+static inline unsigned char random(void);
+
static inline void z8530_isr(struct scc_info *info);
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs);
static void rx_isr(struct scc_priv *priv);
static void special_condition(struct scc_priv *priv, int rc);
static void rx_bh(void *arg);
@@ -255,12 +261,6 @@ static void tx_isr(struct scc_priv *priv);
static void es_isr(struct scc_priv *priv);
static void tm_isr(struct scc_priv *priv);
-static inline void tx_on(struct scc_priv *priv);
-static inline void rx_on(struct scc_priv *priv);
-static inline void rx_off(struct scc_priv *priv);
-static void start_timer(struct scc_priv *priv, int t, int r15);
-static inline unsigned char random(void);
-
/* Initialization variables */
@@ -945,42 +945,115 @@ static int scc_set_mac_address(struct net_device *dev, void *sa) {
}
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) {
- struct scc_info *info = dev_id;
+static inline void tx_on(struct scc_priv *priv) {
+ int i, n;
+ unsigned long flags;
- spin_lock(info->priv[0].register_lock);
- /* At this point interrupts are enabled, and the interrupt under service
- is already acknowledged, but masked off.
+ if (priv->param.dma >= 0) {
+ n = (priv->chip == Z85230) ? 3 : 1;
+ /* Program DMA controller */
+ flags = claim_dma_lock();
+ set_dma_mode(priv->param.dma, DMA_MODE_WRITE);
+ set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n);
+ set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n);
+ release_dma_lock(flags);
+ /* Enable TX underrun interrupt */
+ write_scc(priv, R15, TxUIE);
+ /* Configure DREQ */
+ if (priv->type == TYPE_TWIN)
+ outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
+ priv->card_base + TWIN_DMA_CFG);
+ else
+ write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);
+ /* Write first byte(s) */
+ spin_lock_irqsave(priv->register_lock, flags);
+ for (i = 0; i < n; i++)
+ write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1);
+ enable_dma(priv->param.dma);
+ spin_unlock_irqrestore(priv->register_lock, flags);
+ } else {
+ write_scc(priv, R15, TxUIE);
+ write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
+ tx_isr(priv);
+ }
+ /* Reset EOM latch if we do not have the AUTOEOM feature */
+ if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L);
+}
- Interrupt processing: We loop until we know that the IRQ line is
- low. If another positive edge occurs afterwards during the ISR,
- another interrupt will be triggered by the interrupt controller
- as soon as the IRQ level is enabled again (see asm/irq.h).
- Bottom-half handlers will be processed after scc_isr(). This is
- important, since we only have small ringbuffers and want new data
- to be fetched/delivered immediately. */
+static inline void rx_on(struct scc_priv *priv) {
+ unsigned long flags;
- if (info->priv[0].type == TYPE_TWIN) {
- int is, card_base = info->priv[0].card_base;
- while ((is = ~inb(card_base + TWIN_INT_REG)) &
- TWIN_INT_MSK) {
- if (is & TWIN_SCC_MSK) {
- z8530_isr(info);
- } else if (is & TWIN_TMR1_MSK) {
- inb(card_base + TWIN_CLR_TMR1);
- tm_isr(&info->priv[0]);
- } else {
- inb(card_base + TWIN_CLR_TMR2);
- tm_isr(&info->priv[1]);
- }
+ /* Clear RX FIFO */
+ while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv);
+ priv->rx_over = 0;
+ if (priv->param.dma >= 0) {
+ /* Program DMA controller */
+ flags = claim_dma_lock();
+ set_dma_mode(priv->param.dma, DMA_MODE_READ);
+ set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]);
+ set_dma_count(priv->param.dma, BUF_SIZE);
+ release_dma_lock(flags);
+ enable_dma(priv->param.dma);
+ /* Configure PackeTwin DMA */
+ if (priv->type == TYPE_TWIN) {
+ outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
+ priv->card_base + TWIN_DMA_CFG);
}
- } else z8530_isr(info);
- spin_unlock(info->priv[0].register_lock);
- return IRQ_HANDLED;
+ /* Sp. cond. intr. only, ext int enable, RX DMA enable */
+ write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx |
+ WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
+ } else {
+ /* Reset current frame */
+ priv->rx_ptr = 0;
+ /* Intr. on all Rx characters and Sp. cond., ext int enable */
+ write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
+ WT_FN_RDYFN);
+ }
+ write_scc(priv, R0, ERR_RES);
+ write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB);
+}
+
+
+static inline void rx_off(struct scc_priv *priv) {
+ /* Disable receiver */
+ write_scc(priv, R3, Rx8);
+ /* Disable DREQ / RX interrupt */
+ if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
+ outb(0, priv->card_base + TWIN_DMA_CFG);
+ else
+ write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
+ /* Disable DMA */
+ if (priv->param.dma >= 0) disable_dma(priv->param.dma);
+}
+
+
+static void start_timer(struct scc_priv *priv, int t, int r15) {
+ unsigned long flags;
+
+ outb(priv->tmr_mode, priv->tmr_ctrl);
+ if (t == 0) {
+ tm_isr(priv);
+ } else if (t > 0) {
+ save_flags(flags);
+ cli();
+ outb(t & 0xFF, priv->tmr_cnt);
+ outb((t >> 8) & 0xFF, priv->tmr_cnt);
+ if (priv->type != TYPE_TWIN) {
+ write_scc(priv, R15, r15 | CTSIE);
+ priv->rr0 |= CTS;
+ }
+ restore_flags(flags);
+ }
}
+static inline unsigned char random(void) {
+ /* See "Numerical Recipes in C", second edition, p. 284 */
+ rand = rand * 1664525L + 1013904223L;
+ return (unsigned char) (rand >> 24);
+}
+
static inline void z8530_isr(struct scc_info *info) {
int is, i = 100;
@@ -1009,6 +1082,42 @@ static inline void z8530_isr(struct scc_info *info) {
}
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) {
+ struct scc_info *info = dev_id;
+
+ spin_lock(info->priv[0].register_lock);
+ /* At this point interrupts are enabled, and the interrupt under service
+ is already acknowledged, but masked off.
+
+ Interrupt processing: We loop until we know that the IRQ line is
+ low. If another positive edge occurs afterwards during the ISR,
+ another interrupt will be triggered by the interrupt controller
+ as soon as the IRQ level is enabled again (see asm/irq.h).
+
+ Bottom-half handlers will be processed after scc_isr(). This is
+ important, since we only have small ringbuffers and want new data
+ to be fetched/delivered immediately. */
+
+ if (info->priv[0].type == TYPE_TWIN) {
+ int is, card_base = info->priv[0].card_base;
+ while ((is = ~inb(card_base + TWIN_INT_REG)) &
+ TWIN_INT_MSK) {
+ if (is & TWIN_SCC_MSK) {
+ z8530_isr(info);
+ } else if (is & TWIN_TMR1_MSK) {
+ inb(card_base + TWIN_CLR_TMR1);
+ tm_isr(&info->priv[0]);
+ } else {
+ inb(card_base + TWIN_CLR_TMR2);
+ tm_isr(&info->priv[1]);
+ }
+ }
+ } else z8530_isr(info);
+ spin_unlock(info->priv[0].register_lock);
+ return IRQ_HANDLED;
+}
+
+
static void rx_isr(struct scc_priv *priv) {
if (priv->param.dma >= 0) {
/* Check special condition and perform error reset. See 2.4.7.5. */
@@ -1292,114 +1401,3 @@ static void tm_isr(struct scc_priv *priv) {
break;
}
}
-
-
-static inline void tx_on(struct scc_priv *priv) {
- int i, n;
- unsigned long flags;
-
- if (priv->param.dma >= 0) {
- n = (priv->chip == Z85230) ? 3 : 1;
- /* Program DMA controller */
- flags = claim_dma_lock();
- set_dma_mode(priv->param.dma, DMA_MODE_WRITE);
- set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n);
- set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n);
- release_dma_lock(flags);
- /* Enable TX underrun interrupt */
- write_scc(priv, R15, TxUIE);
- /* Configure DREQ */
- if (priv->type == TYPE_TWIN)
- outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,
- priv->card_base + TWIN_DMA_CFG);
- else
- write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);
- /* Write first byte(s) */
- spin_lock_irqsave(priv->register_lock, flags);
- for (i = 0; i < n; i++)
- write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1);
- enable_dma(priv->param.dma);
- spin_unlock_irqrestore(priv->register_lock, flags);
- } else {
- write_scc(priv, R15, TxUIE);
- write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);
- tx_isr(priv);
- }
- /* Reset EOM latch if we do not have the AUTOEOM feature */
- if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L);
-}
-
-
-static inline void rx_on(struct scc_priv *priv) {
- unsigned long flags;
-
- /* Clear RX FIFO */
- while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv);
- priv->rx_over = 0;
- if (priv->param.dma >= 0) {
- /* Program DMA controller */
- flags = claim_dma_lock();
- set_dma_mode(priv->param.dma, DMA_MODE_READ);
- set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]);
- set_dma_count(priv->param.dma, BUF_SIZE);
- release_dma_lock(flags);
- enable_dma(priv->param.dma);
- /* Configure PackeTwin DMA */
- if (priv->type == TYPE_TWIN) {
- outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,
- priv->card_base + TWIN_DMA_CFG);
- }
- /* Sp. cond. intr. only, ext int enable, RX DMA enable */
- write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx |
- WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);
- } else {
- /* Reset current frame */
- priv->rx_ptr = 0;
- /* Intr. on all Rx characters and Sp. cond., ext int enable */
- write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |
- WT_FN_RDYFN);
- }
- write_scc(priv, R0, ERR_RES);
- write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB);
-}
-
-
-static inline void rx_off(struct scc_priv *priv) {
- /* Disable receiver */
- write_scc(priv, R3, Rx8);
- /* Disable DREQ / RX interrupt */
- if (priv->param.dma >= 0 && priv->type == TYPE_TWIN)
- outb(0, priv->card_base + TWIN_DMA_CFG);
- else
- write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN);
- /* Disable DMA */
- if (priv->param.dma >= 0) disable_dma(priv->param.dma);
-}
-
-
-static void start_timer(struct scc_priv *priv, int t, int r15) {
- unsigned long flags;
-
- outb(priv->tmr_mode, priv->tmr_ctrl);
- if (t == 0) {
- tm_isr(priv);
- } else if (t > 0) {
- save_flags(flags);
- cli();
- outb(t & 0xFF, priv->tmr_cnt);
- outb((t >> 8) & 0xFF, priv->tmr_cnt);
- if (priv->type != TYPE_TWIN) {
- write_scc(priv, R15, r15 | CTSIE);
- priv->rr0 |= CTS;
- }
- restore_flags(flags);
- }
-}
-
-
-static inline unsigned char random(void) {
- /* See "Numerical Recipes in C", second edition, p. 284 */
- rand = rand * 1664525L + 1013904223L;
- return (unsigned char) (rand >> 24);
-}
-
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 78ae4b2aca2c8..4f5256eb8bfea 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -2910,10 +2910,15 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
int ioaddr = pci_resource_start(pdev, 0);
u_short pci_command;
int err;
-
+
if (!dev)
return -ENOMEM;
+ if (pci_enable_device(pdev)) {
+ err = -ENODEV;
+ goto out0;
+ }
+
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -2951,6 +2956,8 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
release_region(dev->base_addr, HP100_REGION_SIZE);
out1:
free_netdev(dev);
+ pci_disable_device(pdev);
+ out0:
return err;
}
@@ -2959,6 +2966,7 @@ static void __devexit hp100_pci_remove (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
cleanup_dev(dev);
+ pci_disable_device(pdev);
}
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index a93cda669010b..d185d573c0305 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -1172,9 +1172,14 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
u32 vendor, model, rev;
int err;
+ if (pci_enable_device(pdev))
+ return -ENODEV;
+
dev = alloc_etherdev(sizeof(struct ioc3_private));
- if (!dev)
- return -ENOMEM;
+ if (!dev) {
+ err = -ENOMEM;
+ goto out_disable;
+ }
err = pci_request_regions(pdev, "ioc3");
if (err)
@@ -1269,6 +1274,8 @@ out_res:
pci_release_regions(pdev);
out_free:
free_netdev(dev);
+out_disable:
+ pci_disable_device(pdev);
return err;
}
@@ -1282,6 +1289,7 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev)
iounmap(ioc3);
pci_release_regions(pdev);
free_netdev(dev);
+ pci_disable_device(pdev);
}
static struct pci_device_id ioc3_pci_tbl[] = {
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index f28ab3346dd80..26af3785dd56f 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -55,6 +55,8 @@ MODULE_DEVICE_TABLE(pci, ixgb_pci_tbl);
/* Local Function Prototypes */
+static inline void ixgb_irq_disable(struct ixgb_adapter *adapter);
+static inline void ixgb_irq_enable(struct ixgb_adapter *adapter);
int ixgb_up(struct ixgb_adapter *adapter);
void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog);
void ixgb_reset(struct ixgb_adapter *adapter);
@@ -82,10 +84,11 @@ static struct net_device_stats *ixgb_get_stats(struct net_device *netdev);
static int ixgb_change_mtu(struct net_device *netdev, int new_mtu);
static int ixgb_set_mac(struct net_device *netdev, void *p);
static void ixgb_update_stats(struct ixgb_adapter *adapter);
-static inline void ixgb_irq_disable(struct ixgb_adapter *adapter);
-static inline void ixgb_irq_enable(struct ixgb_adapter *adapter);
static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs);
static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
+static inline void ixgb_rx_checksum(struct ixgb_adapter *adapter,
+ struct ixgb_rx_desc *rx_desc,
+ struct sk_buff *skb);
#ifdef CONFIG_IXGB_NAPI
static int ixgb_clean(struct net_device *netdev, int *budget);
static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter,
@@ -95,9 +98,6 @@ static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter);
#endif
static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter);
static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
-static inline void ixgb_rx_checksum(struct ixgb_adapter *adapter,
- struct ixgb_rx_desc *rx_desc,
- struct sk_buff *skb);
static void ixgb_tx_timeout(struct net_device *dev);
static void ixgb_tx_timeout_task(struct net_device *dev);
static void ixgb_vlan_rx_register(struct net_device *netdev,
@@ -185,6 +185,34 @@ static void __exit ixgb_exit_module(void)
module_exit(ixgb_exit_module);
+/**
+ * ixgb_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static inline void ixgb_irq_disable(struct ixgb_adapter *adapter)
+{
+ atomic_inc(&adapter->irq_sem);
+ IXGB_WRITE_REG(&adapter->hw, IMC, ~0);
+ IXGB_WRITE_FLUSH(&adapter->hw);
+ synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * ixgb_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static inline void ixgb_irq_enable(struct ixgb_adapter *adapter)
+{
+ if (atomic_dec_and_test(&adapter->irq_sem)) {
+ IXGB_WRITE_REG(&adapter->hw, IMS,
+ IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW |
+ IXGB_INT_RXO | IXGB_INT_LSC);
+ IXGB_WRITE_FLUSH(&adapter->hw);
+ }
+}
+
int ixgb_up(struct ixgb_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -1550,34 +1578,6 @@ static void ixgb_update_stats(struct ixgb_adapter *adapter)
adapter->net_stats.tx_window_errors = 0;
}
-/**
- * ixgb_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-
-static inline void ixgb_irq_disable(struct ixgb_adapter *adapter)
-{
- atomic_inc(&adapter->irq_sem);
- IXGB_WRITE_REG(&adapter->hw, IMC, ~0);
- IXGB_WRITE_FLUSH(&adapter->hw);
- synchronize_irq(adapter->pdev->irq);
-}
-
-/**
- * ixgb_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- **/
-
-static inline void ixgb_irq_enable(struct ixgb_adapter *adapter)
-{
- if (atomic_dec_and_test(&adapter->irq_sem)) {
- IXGB_WRITE_REG(&adapter->hw, IMS,
- IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW |
- IXGB_INT_RXO | IXGB_INT_LSC);
- IXGB_WRITE_FLUSH(&adapter->hw);
- }
-}
-
#define IXGB_MAX_INTR 10
/**
* ixgb_intr - Interrupt Handler
@@ -1730,6 +1730,39 @@ static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter)
}
/**
+ * ixgb_rx_checksum - Receive Checksum Offload for 82597.
+ * @adapter: board private structure
+ * @rx_desc: receive descriptor
+ * @sk_buff: socket buffer with received data
+ **/
+
+static inline void
+ixgb_rx_checksum(struct ixgb_adapter *adapter,
+ struct ixgb_rx_desc *rx_desc, struct sk_buff *skb)
+{
+ /* Ignore Checksum bit is set OR
+ * TCP Checksum has not been calculated
+ */
+ if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) ||
+ (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) {
+ skb->ip_summed = CHECKSUM_NONE;
+ return;
+ }
+
+ /* At this point we know the hardware did the TCP checksum */
+ /* now look at the TCP checksum error bit */
+ if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) {
+ /* let the stack verify checksum errors */
+ skb->ip_summed = CHECKSUM_NONE;
+ adapter->hw_csum_rx_error++;
+ } else {
+ /* TCP checksum is good */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_rx_good++;
+ }
+}
+
+/**
* ixgb_clean_rx_irq - Send received data up the network stack,
* @adapter: board private structure
**/
@@ -1956,39 +1989,6 @@ static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
/**
- * ixgb_rx_checksum - Receive Checksum Offload for 82597.
- * @adapter: board private structure
- * @rx_desc: receive descriptor
- * @sk_buff: socket buffer with received data
- **/
-
-static inline void
-ixgb_rx_checksum(struct ixgb_adapter *adapter,
- struct ixgb_rx_desc *rx_desc, struct sk_buff *skb)
-{
- /* Ignore Checksum bit is set OR
- * TCP Checksum has not been calculated
- */
- if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) ||
- (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) {
- skb->ip_summed = CHECKSUM_NONE;
- return;
- }
-
- /* At this point we know the hardware did the TCP checksum */
- /* now look at the TCP checksum error bit */
- if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) {
- /* let the stack verify checksum errors */
- skb->ip_summed = CHECKSUM_NONE;
- adapter->hw_csum_rx_error++;
- } else {
- /* TCP checksum is good */
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- adapter->hw_csum_rx_good++;
- }
-}
-
-/**
* ixgb_vlan_rx_register - enables or disables vlan tagging/stripping.
*
* @param netdev network interface device structure
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 059f1a68a75ba..402f779ffa595 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1139,6 +1139,49 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
return IRQ_HANDLED;
}
+static inline void rr_raz_tx(struct rr_private *rrpriv,
+ struct net_device *dev)
+{
+ int i;
+
+ for (i = 0; i < TX_RING_ENTRIES; i++) {
+ struct sk_buff *skb = rrpriv->tx_skbuff[i];
+
+ if (skb) {
+ struct tx_desc *desc = &(rrpriv->tx_ring[i]);
+
+ pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo,
+ skb->len, PCI_DMA_TODEVICE);
+ desc->size = 0;
+ set_rraddr(&desc->addr, 0);
+ dev_kfree_skb(skb);
+ rrpriv->tx_skbuff[i] = NULL;
+ }
+ }
+}
+
+
+static inline void rr_raz_rx(struct rr_private *rrpriv,
+ struct net_device *dev)
+{
+ int i;
+
+ for (i = 0; i < RX_RING_ENTRIES; i++) {
+ struct sk_buff *skb = rrpriv->rx_skbuff[i];
+
+ if (skb) {
+ struct rx_desc *desc = &(rrpriv->rx_ring[i]);
+
+ pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo,
+ dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE);
+ desc->size = 0;
+ set_rraddr(&desc->addr, 0);
+ dev_kfree_skb(skb);
+ rrpriv->rx_skbuff[i] = NULL;
+ }
+ }
+}
+
static void rr_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
@@ -1254,49 +1297,6 @@ static int rr_open(struct net_device *dev)
}
-static inline void rr_raz_tx(struct rr_private *rrpriv,
- struct net_device *dev)
-{
- int i;
-
- for (i = 0; i < TX_RING_ENTRIES; i++) {
- struct sk_buff *skb = rrpriv->tx_skbuff[i];
-
- if (skb) {
- struct tx_desc *desc = &(rrpriv->tx_ring[i]);
-
- pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo,
- skb->len, PCI_DMA_TODEVICE);
- desc->size = 0;
- set_rraddr(&desc->addr, 0);
- dev_kfree_skb(skb);
- rrpriv->tx_skbuff[i] = NULL;
- }
- }
-}
-
-
-static inline void rr_raz_rx(struct rr_private *rrpriv,
- struct net_device *dev)
-{
- int i;
-
- for (i = 0; i < RX_RING_ENTRIES; i++) {
- struct sk_buff *skb = rrpriv->rx_skbuff[i];
-
- if (skb) {
- struct rx_desc *desc = &(rrpriv->rx_ring[i]);
-
- pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo,
- dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE);
- desc->size = 0;
- set_rraddr(&desc->addr, 0);
- dev_kfree_skb(skb);
- rrpriv->rx_skbuff[i] = NULL;
- }
- }
-}
-
static void rr_dump(struct net_device *dev)
{
struct rr_private *rrpriv;
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 7488071bfcbc0..6b452e57e9860 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -110,10 +110,7 @@
#include <linux/module.h>
#include <linux/init.h>
-
-#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
-#endif
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
@@ -5113,9 +5110,12 @@ static void __devexit skge_remove_one(struct pci_dev *pdev)
if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2)
have_second_mac = 1;
+ remove_proc_entry(dev->name, pSkRootDir);
unregister_netdev(dev);
- if (have_second_mac)
+ if (have_second_mac) {
+ remove_proc_entry(pAC->dev[1]->name, pSkRootDir);
unregister_netdev(pAC->dev[1]);
+ }
SkGeYellowLED(pAC, pAC->IoBase, 0);
@@ -5182,9 +5182,9 @@ static int __init skge_init(void)
{
int error;
+#ifdef CONFIG_PROC_FS
memcpy(&SK_Root_Dir_entry, BOOT_STRING, sizeof(SK_Root_Dir_entry) - 1);
-#ifdef CONFIG_PROC_FS
pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net);
if (!pSkRootDir) {
printk(KERN_WARNING "Unable to create /proc/net/%s",
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 8ee249a3871ed..f5071b047315d 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -1191,133 +1191,6 @@ static void smc_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-/*--------------------------------------------------------------------
- .
- . This is the main routine of the driver, to handle the device when
- . it needs some attention.
- .
- . So:
- . first, save state of the chipset
- . branch off into routines to handle each case, and acknowledge
- . each to the interrupt register
- . and finally restore state.
- .
- ---------------------------------------------------------------------*/
-
-static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
-{
- struct net_device *dev = dev_id;
- int ioaddr = dev->base_addr;
- struct smc_local *lp = netdev_priv(dev);
-
- byte status;
- word card_stats;
- byte mask;
- int timeout;
- /* state registers */
- word saved_bank;
- word saved_pointer;
- int handled = 0;
-
-
- PRINTK3((CARDNAME": SMC interrupt started \n"));
-
- saved_bank = inw( ioaddr + BANK_SELECT );
-
- SMC_SELECT_BANK(2);
- saved_pointer = inw( ioaddr + POINTER );
-
- mask = inb( ioaddr + INT_MASK );
- /* clear all interrupts */
- outb( 0, ioaddr + INT_MASK );
-
-
- /* set a timeout value, so I don't stay here forever */
- timeout = 4;
-
- PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));
- do {
- /* read the status flag, and mask it */
- status = inb( ioaddr + INTERRUPT ) & mask;
- if (!status )
- break;
-
- handled = 1;
-
- PRINTK3((KERN_WARNING CARDNAME
- ": Handling interrupt status %x \n", status ));
-
- if (status & IM_RCV_INT) {
- /* Got a packet(s). */
- PRINTK2((KERN_WARNING CARDNAME
- ": Receive Interrupt\n"));
- smc_rcv(dev);
- } else if (status & IM_TX_INT ) {
- PRINTK2((KERN_WARNING CARDNAME
- ": TX ERROR handled\n"));
- smc_tx(dev);
- outb(IM_TX_INT, ioaddr + INTERRUPT );
- } else if (status & IM_TX_EMPTY_INT ) {
- /* update stats */
- SMC_SELECT_BANK( 0 );
- card_stats = inw( ioaddr + COUNTER );
- /* single collisions */
- lp->stats.collisions += card_stats & 0xF;
- card_stats >>= 4;
- /* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
-
- /* these are for when linux supports these statistics */
-
- SMC_SELECT_BANK( 2 );
- PRINTK2((KERN_WARNING CARDNAME
- ": TX_BUFFER_EMPTY handled\n"));
- outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
- mask &= ~IM_TX_EMPTY_INT;
- lp->stats.tx_packets += lp->packets_waiting;
- lp->packets_waiting = 0;
-
- } else if (status & IM_ALLOC_INT ) {
- PRINTK2((KERN_DEBUG CARDNAME
- ": Allocation interrupt \n"));
- /* clear this interrupt so it doesn't happen again */
- mask &= ~IM_ALLOC_INT;
-
- smc_hardware_send_packet( dev );
-
- /* enable xmit interrupts based on this */
- mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
-
- /* and let the card send more packets to me */
- netif_wake_queue(dev);
-
- PRINTK2((CARDNAME": Handoff done successfully.\n"));
- } else if (status & IM_RX_OVRN_INT ) {
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
- outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
- } else if (status & IM_EPH_INT ) {
- PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
- } else if (status & IM_ERCV_INT ) {
- PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n"));
- outb( IM_ERCV_INT, ioaddr + INTERRUPT );
- }
- } while ( timeout -- );
-
-
- /* restore state register */
- SMC_SELECT_BANK( 2 );
- outb( mask, ioaddr + INT_MASK );
-
- PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask ));
- outw( saved_pointer, ioaddr + POINTER );
-
- SMC_SELECT_BANK( saved_bank );
-
- PRINTK3((CARDNAME ": Interrupt done\n"));
- return IRQ_RETVAL(handled);
-}
-
/*-------------------------------------------------------------
.
. smc_rcv - receive a packet from the card
@@ -1509,6 +1382,134 @@ static void smc_tx( struct net_device * dev )
return;
}
+/*--------------------------------------------------------------------
+ .
+ . This is the main routine of the driver, to handle the device when
+ . it needs some attention.
+ .
+ . So:
+ . first, save state of the chipset
+ . branch off into routines to handle each case, and acknowledge
+ . each to the interrupt register
+ . and finally restore state.
+ .
+ ---------------------------------------------------------------------*/
+
+static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = dev_id;
+ int ioaddr = dev->base_addr;
+ struct smc_local *lp = netdev_priv(dev);
+
+ byte status;
+ word card_stats;
+ byte mask;
+ int timeout;
+ /* state registers */
+ word saved_bank;
+ word saved_pointer;
+ int handled = 0;
+
+
+ PRINTK3((CARDNAME": SMC interrupt started \n"));
+
+ saved_bank = inw( ioaddr + BANK_SELECT );
+
+ SMC_SELECT_BANK(2);
+ saved_pointer = inw( ioaddr + POINTER );
+
+ mask = inb( ioaddr + INT_MASK );
+ /* clear all interrupts */
+ outb( 0, ioaddr + INT_MASK );
+
+
+ /* set a timeout value, so I don't stay here forever */
+ timeout = 4;
+
+ PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));
+ do {
+ /* read the status flag, and mask it */
+ status = inb( ioaddr + INTERRUPT ) & mask;
+ if (!status )
+ break;
+
+ handled = 1;
+
+ PRINTK3((KERN_WARNING CARDNAME
+ ": Handling interrupt status %x \n", status ));
+
+ if (status & IM_RCV_INT) {
+ /* Got a packet(s). */
+ PRINTK2((KERN_WARNING CARDNAME
+ ": Receive Interrupt\n"));
+ smc_rcv(dev);
+ } else if (status & IM_TX_INT ) {
+ PRINTK2((KERN_WARNING CARDNAME
+ ": TX ERROR handled\n"));
+ smc_tx(dev);
+ outb(IM_TX_INT, ioaddr + INTERRUPT );
+ } else if (status & IM_TX_EMPTY_INT ) {
+ /* update stats */
+ SMC_SELECT_BANK( 0 );
+ card_stats = inw( ioaddr + COUNTER );
+ /* single collisions */
+ lp->stats.collisions += card_stats & 0xF;
+ card_stats >>= 4;
+ /* multiple collisions */
+ lp->stats.collisions += card_stats & 0xF;
+
+ /* these are for when linux supports these statistics */
+
+ SMC_SELECT_BANK( 2 );
+ PRINTK2((KERN_WARNING CARDNAME
+ ": TX_BUFFER_EMPTY handled\n"));
+ outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
+ mask &= ~IM_TX_EMPTY_INT;
+ lp->stats.tx_packets += lp->packets_waiting;
+ lp->packets_waiting = 0;
+
+ } else if (status & IM_ALLOC_INT ) {
+ PRINTK2((KERN_DEBUG CARDNAME
+ ": Allocation interrupt \n"));
+ /* clear this interrupt so it doesn't happen again */
+ mask &= ~IM_ALLOC_INT;
+
+ smc_hardware_send_packet( dev );
+
+ /* enable xmit interrupts based on this */
+ mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
+
+ /* and let the card send more packets to me */
+ netif_wake_queue(dev);
+
+ PRINTK2((CARDNAME": Handoff done successfully.\n"));
+ } else if (status & IM_RX_OVRN_INT ) {
+ lp->stats.rx_errors++;
+ lp->stats.rx_fifo_errors++;
+ outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
+ } else if (status & IM_EPH_INT ) {
+ PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
+ } else if (status & IM_ERCV_INT ) {
+ PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n"));
+ outb( IM_ERCV_INT, ioaddr + INTERRUPT );
+ }
+ } while ( timeout -- );
+
+
+ /* restore state register */
+ SMC_SELECT_BANK( 2 );
+ outb( mask, ioaddr + INT_MASK );
+
+ PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask ));
+ outw( saved_pointer, ioaddr + POINTER );
+
+ SMC_SELECT_BANK( saved_bank );
+
+ PRINTK3((CARDNAME ": Interrupt done\n"));
+ return IRQ_RETVAL(handled);
+}
+
+
/*----------------------------------------------------
. smc_close
.
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 849b576347ba7..e0ddf2be907dc 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -879,7 +879,7 @@ static int netdev_open(struct net_device *dev)
if (dev->if_port == 0)
dev->if_port = np->default_port;
- np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+ np->mcastlock = SPIN_LOCK_UNLOCKED;
set_rx_mode(dev);
writew(0, ioaddr + IntrEnable);
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 69e9246d88472..c11a992c858d5 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -895,7 +895,7 @@ static int tok_open(struct net_device *dev)
ti->sram_virt &= ~1; /* to reverse what we do in tok_close */
/* init the spinlock */
- ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+ ti->lock = SPIN_LOCK_UNLOCKED;
init_timer(&ti->tr_timer);
i = tok_init_card(dev);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 962138008b851..05e8947f9047d 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1141,7 +1141,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
lp->asBitValid = TRUE;
lp->timeout = -1;
lp->gendev = gendev;
- lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+ lp->lock = SPIN_LOCK_UNLOCKED;
init_timer(&lp->timer);
de4x5_parse_params(dev);
@@ -1316,7 +1316,7 @@ de4x5_open(struct net_device *dev)
** Re-initialize the DE4X5...
*/
status = de4x5_init(dev);
- lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+ lp->lock = SPIN_LOCK_UNLOCKED;
lp->state = OPEN;
de4x5_dbg_open(dev);
@@ -2242,8 +2242,13 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
return -ENODEV;
/* Ok, the device seems to be for us. */
- if (!(dev = alloc_etherdev (sizeof (struct de4x5_private))))
- return -ENOMEM;
+ if (pci_enable_device (pdev))
+ return -ENODEV;
+
+ if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) {
+ error = -ENOMEM;
+ goto disable_dev;
+ }
lp = netdev_priv(dev);
lp->bus = PCI;
@@ -2327,6 +2332,8 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
release_region (iobase, DE4X5_PCI_TOTAL_SIZE);
free_dev:
free_netdev (dev);
+ disable_dev:
+ pci_disable_device (pdev);
return error;
}
@@ -2341,6 +2348,7 @@ static void __devexit de4x5_pci_remove (struct pci_dev *pdev)
unregister_netdev (dev);
free_netdev (dev);
release_region (iobase, DE4X5_PCI_TOTAL_SIZE);
+ pci_disable_device (pdev);
}
static struct pci_device_id de4x5_pci_tbl[] = {
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index f3298d161cdde..7353f28ccc34b 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -314,13 +314,13 @@ static u16 phy_read_1bit(unsigned long);
static u8 dmfe_sense_speed(struct dmfe_board_info *);
static void dmfe_process_mode(struct dmfe_board_info *);
static void dmfe_timer(unsigned long);
+static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *);
static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *);
static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *);
static void dmfe_dynamic_reset(struct DEVICE *);
static void dmfe_free_rxbuffer(struct dmfe_board_info *);
static void dmfe_init_dm910x(struct DEVICE *);
-static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
static void dmfe_parse_srom(struct dmfe_board_info *);
static void dmfe_program_DM9801(struct dmfe_board_info *, int);
static void dmfe_program_DM9802(struct dmfe_board_info *);
@@ -885,6 +885,20 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
/*
+ * Calculate the CRC valude of the Rx packet
+ * flag = 1 : return the reverse CRC (for the received packet CRC)
+ * 0 : return the normal CRC (for Hash Table index)
+ */
+
+static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
+{
+ u32 crc = crc32(~0, Data, Len);
+ if (flag) crc = ~crc;
+ return crc;
+}
+
+
+/*
* Receive the come packet and pass to upper layer
*/
@@ -1774,20 +1788,6 @@ static u16 phy_read_1bit(unsigned long ioaddr)
/*
- * Calculate the CRC valude of the Rx packet
- * flag = 1 : return the reverse CRC (for the received packet CRC)
- * 0 : return the normal CRC (for Hash Table index)
- */
-
-static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
-{
- u32 crc = crc32(~0, Data, Len);
- if (flag) crc = ~crc;
- return crc;
-}
-
-
-/*
* Parser SROM and media mode
*/
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index e1c6f3c799a02..20bfbb9c7eb68 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -346,7 +346,7 @@ enum rhine_revs {
VT6105L = 0x8A,
VT6107 = 0x8C,
VTunknown2 = 0x8E,
- VT6105M = 0x90,
+ VT6105M = 0x90, /* Management adapter */
};
enum rhine_quirks {
@@ -485,6 +485,7 @@ struct rhine_private {
dma_addr_t tx_bufs_dma;
struct pci_dev *pdev;
+ long pioaddr;
struct net_device_stats stats;
spinlock_t lock;
@@ -593,7 +594,7 @@ static void rhine_power_init(struct net_device *dev)
default:
reason = "Unknown";
}
- printk("%s: Woke system up. Reason: %s.\n",
+ printk(KERN_INFO "%s: Woke system up. Reason: %s.\n",
DRV_NAME, reason);
}
}
@@ -703,7 +704,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
long memaddr;
long ioaddr;
int io_size, phy_id;
- const char *name, *mname;
+ const char *name;
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -718,41 +719,24 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
phy_id = 0;
quirks = 0;
name = "Rhine";
- mname = "unknown";
if (pci_rev < VTunknown0) {
quirks = rqRhineI;
io_size = 128;
- mname = "VT86C100A";
}
else if (pci_rev >= VT6102) {
quirks = rqWOL | rqForceReset;
if (pci_rev < VT6105) {
name = "Rhine II";
quirks |= rqStatusWBRace; /* Rhine-II exclusive */
- if (pci_rev < VT8231)
- mname = "VT6102";
- else if (pci_rev < VT8233)
- mname = "VT8231";
- else if (pci_rev < VT8235)
- mname = "VT8233";
- else if (pci_rev < VT8237)
- mname = "VT8235";
- else if (pci_rev < VTunknown1)
- mname = "VT8237";
}
else {
- name = "Rhine III";
phy_id = 1; /* Integrated PHY, phy_id fixed to 1 */
if (pci_rev >= VT6105_B0)
quirks |= rq6patterns;
- if (pci_rev < VT6105L)
- mname = "VT6105";
- else if (pci_rev < VT6107)
- mname = "VT6105L";
- else if (pci_rev < VT6105M)
- mname = "VT6107";
- else if (pci_rev >= VT6105M)
- mname = "Management Adapter VT6105M";
+ if (pci_rev < VT6105M)
+ name = "Rhine III";
+ else
+ name = "Rhine III (Management Adapter)";
}
}
@@ -790,6 +774,11 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
+ rp = netdev_priv(dev);
+ rp->quirks = quirks;
+ rp->pioaddr = pioaddr;
+ rp->pdev = pdev;
+
rc = pci_request_regions(pdev, DRV_NAME);
if (rc)
goto err_out_free_netdev;
@@ -823,8 +812,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
#endif /* USE_MMIO */
dev->base_addr = ioaddr;
- rp = netdev_priv(dev);
- rp->quirks = quirks;
/* Get chip registers into a sane state */
rhine_power_init(dev);
@@ -846,7 +833,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
dev->irq = pdev->irq;
spin_lock_init(&rp->lock);
- rp->pdev = pdev;
rp->mii_if.dev = dev;
rp->mii_if.mdio_read = mdio_read;
rp->mii_if.mdio_write = mdio_write;
@@ -874,8 +860,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rc)
goto err_out_unmap;
- printk(KERN_INFO "%s: VIA %s (%s) at 0x%lx, ",
- dev->name, name, mname,
+ printk(KERN_INFO "%s: VIA %s at 0x%lx, ",
+ dev->name, name,
#ifdef USE_MMIO
memaddr
#else
@@ -890,7 +876,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
{
+ u16 mii_cmd;
int mii_status = mdio_read(dev, phy_id, 1);
+ mii_cmd = mdio_read(dev, phy_id, MII_BMCR) & ~BMCR_ISOLATE;
+ mdio_write(dev, phy_id, MII_BMCR, mii_cmd);
if (mii_status != 0xffff && mii_status != 0x0000) {
rp->mii_if.advertising = mdio_read(dev, phy_id, 4);
printk(KERN_INFO "%s: MII PHY found at address "
@@ -1172,7 +1161,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum)
rhine_disable_linkmon(ioaddr, rp->quirks);
- writeb(0, ioaddr + MIICmd);
+ /* rhine_disable_linkmon already cleared MIICmd */
writeb(phy_id, ioaddr + MIIPhyAddr);
writeb(regnum, ioaddr + MIIRegAddr);
writeb(0x40, ioaddr + MIICmd); /* Trigger read */
@@ -1190,7 +1179,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value
rhine_disable_linkmon(ioaddr, rp->quirks);
- writeb(0, ioaddr + MIICmd);
+ /* rhine_disable_linkmon already cleared MIICmd */
writeb(phy_id, ioaddr + MIIPhyAddr);
writeb(regnum, ioaddr + MIIRegAddr);
writew(value, ioaddr + MIIData);
@@ -1951,11 +1940,70 @@ static void rhine_shutdown (struct device *gendev)
}
+#ifdef CONFIG_PM
+static int rhine_suspend(struct pci_dev *pdev, u32 state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rhine_private *rp = netdev_priv(dev);
+ unsigned long flags;
+
+ if (!netif_running(dev))
+ return 0;
+
+ netif_device_detach(dev);
+ pci_save_state(pdev, pdev->saved_config_space);
+
+ spin_lock_irqsave(&rp->lock, flags);
+ rhine_shutdown(&pdev->dev);
+ spin_unlock_irqrestore(&rp->lock, flags);
+
+ return 0;
+}
+
+static int rhine_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rhine_private *rp = netdev_priv(dev);
+ unsigned long flags;
+ int ret;
+
+ if (!netif_running(dev))
+ return 0;
+
+ ret = pci_set_power_state(pdev, 0);
+ if (debug > 1)
+ printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n",
+ dev->name, ret ? "failed" : "succeeded", ret);
+
+ pci_restore_state(pdev, pdev->saved_config_space);
+
+ spin_lock_irqsave(&rp->lock, flags);
+#ifdef USE_MMIO
+ enable_mmio(rp->pioaddr, rp->quirks);
+#endif
+ rhine_power_init(dev);
+ free_tbufs(dev);
+ free_rbufs(dev);
+ alloc_tbufs(dev);
+ alloc_rbufs(dev);
+ init_registers(dev);
+ spin_unlock_irqrestore(&rp->lock, flags);
+
+ netif_device_attach(dev);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
static struct pci_driver rhine_driver = {
.name = DRV_NAME,
.id_table = rhine_pci_tbl,
.probe = rhine_init_one,
.remove = __devexit_p(rhine_remove_one),
+#ifdef CONFIG_PM
+ .suspend = rhine_suspend,
+ .resume = rhine_resume,
+#endif /* CONFIG_PM */
.driver = {
.shutdown = rhine_shutdown,
}
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index eb27753972686..f71086737a443 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -262,6 +262,7 @@ static u32 check_connection_type(struct mac_regs * regs);
static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
#ifdef CONFIG_PM
+
static int velocity_suspend(struct pci_dev *pdev, u32 state);
static int velocity_resume(struct pci_dev *pdev);
@@ -270,9 +271,26 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi
static struct notifier_block velocity_inetaddr_notifier = {
.notifier_call = velocity_netdev_event,
};
-static int velocity_notifier_registered;
-#endif /* CONFIG_PM */
+static spinlock_t velocity_dev_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(velocity_dev_list);
+
+static void velocity_register_notifier(void)
+{
+ register_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+static void velocity_unregister_notifier(void)
+{
+ unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+#else /* CONFIG_PM */
+
+#define velocity_register_notifier() do {} while (0)
+#define velocity_unregister_notifier() do {} while (0)
+
+#endif /* !CONFIG_PM */
/*
* Internal board variants. At the moment we have only one
@@ -327,6 +345,14 @@ static void __devexit velocity_remove1(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct velocity_info *vptr = dev->priv;
+#ifdef CONFIG_PM
+ unsigned long flags;
+
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ if (!list_empty(&velocity_dev_list))
+ list_del(&vptr->list);
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
+#endif
unregister_netdev(dev);
iounmap(vptr->mac_regs);
pci_release_regions(pdev);
@@ -782,13 +808,16 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
/* and leave the chip powered down */
pci_set_power_state(pdev, 3);
-out:
#ifdef CONFIG_PM
- if (ret == 0 && !velocity_notifier_registered) {
- velocity_notifier_registered = 1;
- register_inetaddr_notifier(&velocity_inetaddr_notifier);
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_add(&vptr->list, &velocity_dev_list);
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
#endif
+out:
return ret;
err_iounmap:
@@ -843,6 +872,8 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i
spin_lock_init(&vptr->lock);
spin_lock_init(&vptr->xmit_lock);
+
+ INIT_LIST_HEAD(&vptr->list);
}
/**
@@ -2211,8 +2242,11 @@ static struct pci_driver velocity_driver = {
static int __init velocity_init_module(void)
{
int ret;
- ret = pci_module_init(&velocity_driver);
+ velocity_register_notifier();
+ ret = pci_module_init(&velocity_driver);
+ if (ret < 0)
+ velocity_unregister_notifier();
return ret;
}
@@ -2227,12 +2261,7 @@ static int __init velocity_init_module(void)
static void __exit velocity_cleanup_module(void)
{
-#ifdef CONFIG_PM
- if (velocity_notifier_registered) {
- unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
- velocity_notifier_registered = 0;
- }
-#endif
+ velocity_unregister_notifier();
pci_unregister_driver(&velocity_driver);
}
@@ -3252,13 +3281,20 @@ static int velocity_resume(struct pci_dev *pdev)
static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
- struct net_device *dev;
- struct velocity_info *vptr;
if (ifa) {
- dev = ifa->ifa_dev->dev;
- vptr = dev->priv;
- velocity_get_ip(vptr);
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct velocity_info *vptr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_for_each_entry(vptr, &velocity_dev_list, list) {
+ if (vptr->dev == dev) {
+ velocity_get_ip(vptr);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
return NOTIFY_DONE;
}
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 630a466209807..b2c05a8a1aa30 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1733,8 +1733,7 @@ struct velocity_opt {
};
struct velocity_info {
- struct velocity_info *next;
- struct velocity_info *prev;
+ struct list_head list;
struct pci_dev *pdev;
struct net_device *dev;
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index cd1cd85691e86..07bfe107ac5c9 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -186,7 +186,7 @@ static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble),
reset_timer(struct net_device *dev);
static u8 bps_to_speed_code(u32 bps);
-static u8 log2(u32 n);
+static u8 cycx_log2(u32 n);
static unsigned dec_to_uint(u8 *str, int len);
@@ -263,7 +263,7 @@ int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf)
else
card->wandev.mtu = 64;
- cfg.pktlen = log2(card->wandev.mtu);
+ cfg.pktlen = cycx_log2(card->wandev.mtu);
if (conf->station == WANOPT_DTE) {
cfg.locaddr = 3; /* DTE */
@@ -1513,7 +1513,7 @@ static u8 bps_to_speed_code(u32 bps)
}
/* log base 2 */
-static u8 log2(u32 n)
+static u8 cycx_log2(u32 n)
{
u8 log = 0;
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index 6e67ea060f738..45f2be4cccdc3 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -11,7 +11,7 @@
* (at your option) any later version.
*
* by Alan Cox <alan@redhat.com> and
- * Alex deVries <adevries@thepuffingroup.com>
+ * Alex deVries <alex@onefishtwo.ca>
*/
#include <linux/errno.h>
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 1d238caf36beb..0e1426ccd6fa3 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -8,7 +8,7 @@
* (C) Copyright 2000 Linuxcare, Inc.
* (C) Copyright 2000 Linuxcare Canada, Inc.
* (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
- * (C) Copyright 2000 Alex deVries <alex@linuxcare.com>
+ * (C) Copyright 2000 Alex deVries <alex@onefishtwo.ca>
* (C) Copyright 2001 John Marvin <jsm fc hp com>
* (C) Copyright 2003 Grant Grundler <grundler parisc-linux org>
*
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 8391c92d9ac27..4539e61a3dc1f 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -61,7 +61,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
/* export the attention callback registration methods */
EXPORT_SYMBOL_GPL(acpiphp_register_attention);
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c
index cb54fa8ab8b99..0a01b0710f971 100644
--- a/drivers/pci/hotplug/cpcihp_zt5550.c
+++ b/drivers/pci/hotplug/cpcihp_zt5550.c
@@ -298,7 +298,7 @@ module_exit(zt5550_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-module_param(poll, bool, 644);
+module_param(poll, bool, 0644);
MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not");
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index aa8a1a4d7ab18..13d147989bf7a 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -69,10 +69,10 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(power_mode, bool, 644);
+module_param(power_mode, bool, 0644);
MODULE_PARM_DESC(power_mode, "Power mode enabled or not");
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
#define CPQHPC_MODULE_MINOR 208
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 039213c29a167..dff5d88b7d052 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -701,7 +701,7 @@ module_exit(pci_hotplug_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index b31ccbcea9990..9df420db24da7 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -57,9 +57,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(pciehp_debug, bool, 644);
-module_param(pciehp_poll_mode, bool, 644);
-module_param(pciehp_poll_time, int, 644);
+module_param(pciehp_debug, bool, 0644);
+module_param(pciehp_poll_mode, bool, 0644);
+module_param(pciehp_poll_time, int, 0644);
MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c
index f413495a2f2ca..6605d6bda5291 100644
--- a/drivers/pci/hotplug/pcihp_skeleton.c
+++ b/drivers/pci/hotplug/pcihp_skeleton.c
@@ -70,7 +70,7 @@ static int num_slots;
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
static int enable_slot (struct hotplug_slot *slot);
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 7f34ec941976b..4f7a11d87b272 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -57,9 +57,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(shpchp_debug, bool, 644);
-module_param(shpchp_poll_mode, bool, 644);
-module_param(shpchp_poll_time, int, 644);
+module_param(shpchp_debug, bool, 0644);
+module_param(shpchp_poll_mode, bool, 0644);
+module_param(shpchp_poll_time, int, 0644);
MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 9936879eb7194..9f8f56a2d1b59 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -390,10 +390,9 @@ pci_populate_driver_dir(struct pci_driver *drv)
* pci_register_driver - register a new pci driver
* @drv: the driver structure to register
*
- * Adds the driver structure to the list of registered drivers
- * Returns the number of pci devices which were claimed by the driver
- * during registration. The driver remains registered even if the
- * return value is zero.
+ * Adds the driver structure to the list of registered drivers.
+ * Returns a negative value on error. The driver remains registered
+ * even if no device was claimed during registration.
*/
int
pci_register_driver(struct pci_driver *drv)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 9203f89f89c10..b57fe55241134 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -571,6 +571,11 @@ static int pci_cfg_space_size(struct pci_dev *dev)
return PCI_CFG_SPACE_SIZE;
}
+static void pci_release_bus_bridge_dev(struct device *dev)
+{
+ kfree(dev);
+}
+
/*
* Read the config data for a PCI device, sanity-check it
* and fill in the dev structure...
@@ -772,6 +777,7 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
memset(dev, 0, sizeof(*dev));
dev->parent = parent;
+ dev->release = pci_release_bus_bridge_dev;
sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus);
device_register(dev);
b->bridge = get_device(dev);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 5ef19b1758def..889b2e3ac8402 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -59,6 +59,18 @@ int pci_remove_device_safe(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_remove_device_safe);
+void pci_remove_bus(struct pci_bus *b)
+{
+ pci_proc_detach_bus(b);
+
+ spin_lock(&pci_bus_lock);
+ list_del(&b->node);
+ spin_unlock(&pci_bus_lock);
+
+ class_device_unregister(&b->class_dev);
+}
+EXPORT_SYMBOL(pci_remove_bus);
+
/**
* pci_remove_bus_device - remove a PCI device and any children
* @dev: the device to remove
@@ -77,13 +89,7 @@ void pci_remove_bus_device(struct pci_dev *dev)
struct pci_bus *b = dev->subordinate;
pci_remove_behind_bridge(dev);
- pci_proc_detach_bus(b);
-
- spin_lock(&pci_bus_lock);
- list_del(&b->node);
- spin_unlock(&pci_bus_lock);
-
- class_device_unregister(&b->class_dev);
+ pci_remove_bus(b);
dev->subordinate = NULL;
}
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index bd79f3bd13786..124225edcac80 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -566,7 +566,6 @@ static int
au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
{
unsigned int speed;
- unsigned long start;
u_long flags;
if(map->map>=MAX_WIN){
@@ -588,25 +587,19 @@ au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
}
spin_lock_irqsave(&pcmcia_lock, flags);
- start=map->sys_start;
-
- if(map->sys_stop==0)
- map->sys_stop=MAP_SIZE-1;
-
if (map->flags & MAP_ATTRIB) {
- map->sys_start = pcmcia_socket[sock].phys_attr +
+ map->static_start = pcmcia_socket[sock].phys_attr +
map->card_start;
}
else {
- map->sys_start = pcmcia_socket[sock].phys_mem +
+ map->static_start = pcmcia_socket[sock].phys_mem +
map->card_start;
}
- map->sys_stop=map->sys_start+(map->sys_stop-start);
pcmcia_socket[sock].mem_map[map->map]=*map;
spin_unlock_irqrestore(&pcmcia_lock, flags);
- debug(3, "set_mem_map %d start %x stop %x card_start %x\n",
- map->map, map->sys_start, map->sys_stop,
+ debug(3, "set_mem_map %d start %x card_start %x\n",
+ map->map, map->static_start,
map->card_start);
return 0;
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index b78d41a3c8406..4afeab4570718 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -114,8 +114,6 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
printk(KERN_NOTICE "cs: unable to map card memory!\n");
return NULL;
}
- mem->sys_start = mem->res->start;
- mem->sys_stop = mem->res->end;
s->cis_virt = ioremap(mem->res->start, s->map_size);
}
mem->card_start = card_offset;
@@ -124,7 +122,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
if (s->features & SS_CAP_STATIC_MAP) {
if (s->cis_virt)
iounmap(s->cis_virt);
- s->cis_virt = ioremap(mem->sys_start, s->map_size);
+ s->cis_virt = ioremap(mem->static_start, s->map_size);
}
return s->cis_virt;
}
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index f796bc99cff8b..cd9e94d8cb7c3 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -1886,11 +1886,6 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
(*handle)->dev_info, s);
if (!win->ctl.res)
return CS_IN_USE;
- win->ctl.sys_start = win->ctl.res->start;
- win->ctl.sys_stop = win->ctl.res->end;
- } else {
- win->ctl.sys_start = req->Base;
- win->ctl.sys_stop = req->Base + req->Size - 1;
}
(*handle)->state |= CLIENT_WIN_REQ(w);
@@ -1912,7 +1907,11 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
s->state |= SOCKET_WIN_REQ(w);
/* Return window handle */
- req->Base = win->ctl.sys_start;
+ if (s->features & SS_CAP_STATIC_MAP) {
+ req->Base = win->ctl.static_start;
+ } else {
+ req->Base = win->ctl.res->start;
+ }
*wh = win;
return CS_SUCCESS;
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index fd08c3a5b3daf..875c9cfaea3f1 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -636,19 +636,17 @@ static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
struct pccard_mem_map *smem;
int map = mem->map;
- unsigned long paddr, size;
+ unsigned long paddr;
#if 0
- DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, sys_start=0x%08lx, sys_end=0x%08lx, card_start=0x%08x)\n",
- sock, map, mem->flags, mem->sys_start, mem->sys_stop, mem->card_start);
+ DPRINTK("hs_set_mem_map(sock=%d, map=%d, flags=0x%x, card_start=0x%08x)\n",
+ sock, map, mem->flags, mem->card_start);
#endif
if (map >= MAX_WIN)
return -EINVAL;
smem = &sp->mem_maps[map];
- size = mem->sys_stop - mem->sys_start + 1;
-
paddr = sp->mem_base; /* base of Attribute mapping */
if (!(mem->flags & MAP_ATTRIB))
paddr += HD64465_PCC_WINDOW; /* base of Common mapping */
@@ -660,8 +658,7 @@ static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
* queries our fixed mapping. I wish this fact had been
* documented - Greg Banks.
*/
- mem->sys_start = paddr;
- mem->sys_stop = paddr + size - 1;
+ mem->static_start = paddr;
*smem = *mem;
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 3115eb3bc7f1c..eb255238aef8d 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -422,7 +422,7 @@ static int i82092aa_init(struct pcmcia_socket *sock)
int i;
struct resource res = { .start = 0, .end = 0x0fff };
pccard_io_map io = { 0, 0, 0, 0, 1 };
- pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff, };
+ pccard_mem_map mem = { .res = &res, };
enter("i82092aa_init");
@@ -706,11 +706,15 @@ static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_ma
static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem)
{
- unsigned int sock = container_of(socket, struct socket_info, socket)->number;
+ struct socket_info *sock_info = container_of(socket, struct socket_info, socket);
+ unsigned int sock = sock_info->number;
+ struct pci_bus_region region;
unsigned short base, i;
unsigned char map;
enter("i82092aa_set_mem_map");
+
+ pcibios_resource_to_bus(sock_info->dev, &region, mem->res);
map = mem->map;
if (map > 4) {
@@ -719,10 +723,10 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
}
- if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) ||
+ if ( (mem->card_start > 0x3ffffff) || (region.start > region.end) ||
(mem->speed > 1000) ) {
leave("i82092aa_set_mem_map: invalid address / speed");
- printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,mem->sys_start, mem->sys_stop, mem->card_start);
+ printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,region.start, region.end, mem->card_start);
return -EINVAL;
}
@@ -731,11 +735,11 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
-/* printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, mem->sys_start,mem->sys_stop,sock,mem->speed,mem->flags & MAP_ACTIVE); */
+/* printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, region.start,region.end,sock,mem->speed,mem->flags & MAP_ACTIVE); */
/* write the start address */
base = I365_MEM(map);
- i = (mem->sys_start >> 12) & 0x0fff;
+ i = (region.start >> 12) & 0x0fff;
if (mem->flags & MAP_16BIT)
i |= I365_MEM_16BIT;
if (mem->flags & MAP_0WS)
@@ -744,7 +748,7 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
/* write the stop address */
- i= (mem->sys_stop >> 12) & 0x0fff;
+ i= (region.end >> 12) & 0x0fff;
switch (to_cycles(mem->speed)) {
case 0:
break;
@@ -763,7 +767,7 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
/* card start */
- i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+ i = ((mem->card_start - region.start) >> 12) & 0x3fff;
if (mem->flags & MAP_WRPROT)
i |= I365_MEM_WRPROT;
if (mem->flags & MAP_ATTRIB) {
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index b753c31862ed8..9d990af6734df 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1159,13 +1159,13 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
"lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
- mem->sys_start, mem->sys_stop, mem->card_start);
+ mem->res->start, mem->res->end, mem->card_start);
map = mem->map;
if ((map > 4) || (mem->card_start > 0x3ffffff) ||
- (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+ (mem->res->start > mem->res->end) || (mem->speed > 1000))
return -EINVAL;
- if ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff))
+ if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
return -EINVAL;
/* Turn off the window before changing anything */
@@ -1173,12 +1173,12 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
base = I365_MEM(map);
- i = (mem->sys_start >> 12) & 0x0fff;
+ i = (mem->res->start >> 12) & 0x0fff;
if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
i365_set_pair(sock, base+I365_W_START, i);
- i = (mem->sys_stop >> 12) & 0x0fff;
+ i = (mem->res->end >> 12) & 0x0fff;
switch (to_cycles(mem->speed)) {
case 0: break;
case 1: i |= I365_MEM_WS0; break;
@@ -1187,7 +1187,7 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
}
i365_set_pair(sock, base+I365_W_STOP, i);
- i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+ i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
i365_set_pair(sock, base+I365_W_OFF, i);
@@ -1309,7 +1309,7 @@ static int pcic_init(struct pcmcia_socket *s)
int i;
struct resource res = { .start = 0, .end = 0x1000 };
pccard_io_map io = { 0, 0, 0, 0, 1 };
- pccard_mem_map mem = { .res = &res, .sys_stop = 0x1000, };
+ pccard_mem_map mem = { .res = &res, };
for (i = 0; i < 2; i++) {
io.map = i;
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 57b1bca00dcc7..4f00c9dda0754 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -502,10 +502,10 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
return -EINVAL;
}
- if ((mem->sys_start > mem->sys_stop) || (mem->speed > 1000)) {
+ if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) {
printk("pd6729_set_mem_map: invalid address / speed");
/* printk("invalid mem map for socket %i : %lx to %lx with a start of %x\n",
- sock, mem->sys_start, mem->sys_stop, mem->card_start); */
+ sock, mem->res->start, mem->res->end, mem->card_start); */
return -EINVAL;
}
@@ -515,7 +515,7 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
/* write the start address */
base = I365_MEM(map);
- i = (mem->sys_start >> 12) & 0x0fff;
+ i = (mem->res->start >> 12) & 0x0fff;
if (mem->flags & MAP_16BIT)
i |= I365_MEM_16BIT;
if (mem->flags & MAP_0WS)
@@ -524,7 +524,7 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
/* write the stop address */
- i= (mem->sys_stop >> 12) & 0x0fff;
+ i= (mem->res->end >> 12) & 0x0fff;
switch (to_cycles(mem->speed)) {
case 0:
break;
@@ -543,11 +543,11 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
/* Take care of high byte */
indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
- indirect_write(socket, PD67_EXT_DATA, mem->sys_start >> 24);
+ indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24);
/* card start */
- i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+ i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
if (mem->flags & MAP_WRPROT)
i |= I365_MEM_WRPROT;
if (mem->flags & MAP_ATTRIB) {
@@ -577,7 +577,7 @@ static int pd6729_init(struct pcmcia_socket *sock)
int i;
struct resource res = { .end = 0x0fff };
pccard_io_map io = { 0, 0, 0, 0, 1 };
- pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff };
+ pccard_mem_map mem = { .res = &res, };
pd6729_set_socket(sock, &dead_socket);
for (i = 0; i < 2; i++) {
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 6869e209dfbfa..f03d02b582a54 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -301,8 +301,6 @@ static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *in
{
int ret = -1;
- s->cis_mem.sys_start = res->start;
- s->cis_mem.sys_stop = res->end;
s->cis_mem.res = res;
s->cis_virt = ioremap(res->start, s->map_size);
if (s->cis_virt) {
@@ -312,8 +310,6 @@ static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *in
s->cis_virt = NULL;
destroy_cis_cache(s);
}
- s->cis_mem.sys_start = 0;
- s->cis_mem.sys_stop = 0;
s->cis_mem.res = NULL;
if ((ret != 0) || (info->Chains == 0))
return 0;
@@ -332,8 +328,6 @@ static int checksum(struct pcmcia_socket *s, struct resource *res)
map.map = 0;
map.flags = MAP_ACTIVE;
map.speed = 0;
- map.sys_start = res->start;
- map.sys_stop = res->end;
map.res = res;
map.card_start = 0;
s->ops->set_mem_map(s, &map);
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index 6d393e739fc0f..7b084b8937bb7 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -448,9 +448,7 @@ soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map
skt->ops->set_timing(skt);
- map->sys_stop -= map->sys_start;
- map->sys_stop += res->start + map->card_start;
- map->sys_start = res->start + map->card_start;
+ map->static_start = res->start + map->card_start;
return 0;
}
@@ -662,6 +660,7 @@ static void soc_pcmcia_cpufreq_unregister(void)
int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
{
struct skt_dev_info *sinfo;
+ struct soc_pcmcia_socket *skt;
int ret, i;
down(&soc_pcmcia_sockets_lock);
@@ -679,7 +678,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
* Initialise the per-socket structure.
*/
for (i = 0; i < nr; i++) {
- struct soc_pcmcia_socket *skt = &sinfo->skt[i];
+ skt = &sinfo->skt[i];
skt->socket.ops = &soc_common_pcmcia_operations;
skt->socket.owner = ops->owner;
@@ -777,7 +776,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
goto out;
do {
- struct soc_pcmcia_socket *skt = &sinfo->skt[i];
+ skt = &sinfo->skt[i];
del_timer_sync(&skt->poll_timer);
pcmcia_unregister_socket(&skt->socket);
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index f3b38e96dcdc1..d986d13f288bb 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -829,15 +829,15 @@ static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "
"%#5.5lx-%#5.5lx, %#5.5x)\n", psock, mem->map, mem->flags,
- mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+ mem->speed, mem->res->start, mem->res->end, mem->card_start);
if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
- (mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) ||
- (mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+ (mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
+ (mem->res->start > mem->res->end) || (mem->speed > 1000))
return -EINVAL;
tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
addr = TCIC_MWIN(psock, mem->map);
- base = mem->sys_start; len = mem->sys_stop - mem->sys_start;
+ base = mem->res->start; len = mem->res->end - mem->res->start;
if ((len & (len+1)) || (base & len)) return -EINVAL;
if (len == 0x0fff)
base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
@@ -846,7 +846,7 @@ static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
tcic_setw(TCIC_DATA, base);
- mmap = mem->card_start - mem->sys_start;
+ mmap = mem->card_start - mem->res->start;
mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
@@ -870,7 +870,7 @@ static int tcic_init(struct pcmcia_socket *s)
int i;
struct resource res = { .start = 0, .end = 0x1000 };
pccard_io_map io = { 0, 0, 0, 0, 1 };
- pccard_mem_map mem = { .res = &res, .sys_stop = 0x1000, };
+ pccard_mem_map mem = { .res = &res, };
for (i = 0; i < 2; i++) {
io.map = i;
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 4c8a7a5724d61..87a95cc5d9c49 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -343,14 +343,17 @@ static int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io
static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
{
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+ struct pci_bus_region region;
int map;
unsigned char addr, enable;
unsigned int start, stop, card_start;
unsigned short word;
+ pcibios_resource_to_bus(socket->dev, &region, mem->res);
+
map = mem->map;
- start = mem->sys_start;
- stop = mem->sys_stop;
+ start = region.start;
+ stop = region.end;
card_start = mem->card_start;
if (map > 4 || start > stop || ((start ^ stop) >> 24) ||
@@ -447,7 +450,7 @@ static void yenta_clear_maps(struct yenta_socket *socket)
int i;
struct resource res = { .start = 0, .end = 0x0fff };
pccard_io_map io = { 0, 0, 0, 0, 1 };
- pccard_mem_map mem = { .res = &res, .sys_stop = 0x0fff, };
+ pccard_mem_map mem = { .res = &res, };
yenta_set_socket(&socket->socket, &dead_socket);
for (i = 0; i < 2; i++) {
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index dad02890ef01e..e57bd06f5b6b8 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -29,7 +29,7 @@
*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_AUX_REVISION "$Revision: 1.115 $"
+#define ZFCP_AUX_REVISION "$Revision: 1.121 $"
#include "zfcp_ext.h"
@@ -48,10 +48,10 @@ static void zfcp_ns_gid_pn_handler(unsigned long);
static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
static inline int zfcp_sg_list_free(struct zfcp_sg_list *);
-static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, void *,
- size_t);
-static inline int zfcp_sg_list_copy_to_user(void *, struct zfcp_sg_list *,
- size_t);
+static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
+ void __user *, size_t);
+static inline int zfcp_sg_list_copy_to_user(void __user *,
+ struct zfcp_sg_list *, size_t);
static int zfcp_cfdc_dev_ioctl(struct inode *, struct file *,
unsigned int, unsigned long);
@@ -95,7 +95,7 @@ MODULE_PARM_DESC(device, "specify initial device");
module_param(loglevel, uint, 0);
MODULE_PARM_DESC(loglevel,
"log levels, 8 nibbles: "
- "(unassigned) ERP QDIO DIO Config FSF SCSI Other, "
+ "(unassigned) FC ERP QDIO CIO Config FSF SCSI Other, "
"levels: 0=none 1=normal 2=devel 3=trace");
#ifdef ZFCP_PRINT_FLAGS
@@ -382,7 +382,7 @@ static int
zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
unsigned int command, unsigned long buffer)
{
- struct zfcp_cfdc_sense_data sense_data, *sense_data_user;
+ struct zfcp_cfdc_sense_data sense_data, __user *sense_data_user;
struct zfcp_adapter *adapter = NULL;
struct zfcp_fsf_req *fsf_req = NULL;
struct zfcp_sg_list *sg_list = NULL;
@@ -403,7 +403,7 @@ zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
goto out;
}
- if ((sense_data_user = (struct zfcp_cfdc_sense_data*)buffer) == NULL) {
+ if ((sense_data_user = (void __user *) buffer) == NULL) {
ZFCP_LOG_INFO("sense data record is required\n");
retval = -EINVAL;
goto out;
@@ -520,6 +520,12 @@ zfcp_cfdc_dev_ioctl(struct inode *inode, struct file *file,
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+ if ((fsf_req->qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
+ (fsf_req->qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
+ retval = -ENXIO;
+ goto out;
+ }
+
sense_data.fsf_status = fsf_req->qtcb->header.fsf_status;
memcpy(&sense_data.fsf_status_qual,
&fsf_req->qtcb->header.fsf_status_qual,
@@ -637,7 +643,8 @@ zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
* -EFAULT - Memory I/O operation fault
*/
static inline int
-zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer,
+zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
+ void __user *user_buffer,
size_t size)
{
struct scatterlist *sg;
@@ -671,7 +678,8 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void *user_buffer,
* -EFAULT - Memory I/O operation fault
*/
static inline int
-zfcp_sg_list_copy_to_user(void *user_buffer, struct zfcp_sg_list *sg_list,
+zfcp_sg_list_copy_to_user(void __user *user_buffer,
+ struct zfcp_sg_list *sg_list,
size_t size)
{
struct scatterlist *sg;
@@ -1646,15 +1654,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
ct_iu_req = zfcp_sg_to_address(ct->req);
ct_iu_resp = zfcp_sg_to_address(ct->resp);
- if (ct_iu_resp->header.revision != ZFCP_CT_REVISION)
- goto failed;
- if (ct_iu_resp->header.gs_type != ZFCP_CT_DIRECTORY_SERVICE)
- goto failed;
- if (ct_iu_resp->header.gs_subtype != ZFCP_CT_NAME_SERVER)
- goto failed;
- if (ct_iu_resp->header.options != ZFCP_CT_SYNCHRONOUS)
- goto failed;
- if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) {
+ if (zfcp_check_ct_response(&ct_iu_resp->header)) {
/* FIXME: do we need some specific erp entry points */
atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status);
goto failed;
@@ -1675,7 +1675,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
zfcp_get_busid_by_port(port), port->wwpn, port->d_id);
goto out;
-failed:
+ failed:
ZFCP_LOG_NORMAL("warning: failed gid_pn nameserver request for wwpn "
"0x%016Lx for adapter %s\n",
port->wwpn, zfcp_get_busid_by_port(port));
@@ -1690,4 +1690,169 @@ failed:
return;
}
+/* reject CT_IU reason codes acc. to FC-GS-4 */
+static const struct zfcp_rc_entry zfcp_ct_rc[] = {
+ {0x01, "invalid command code"},
+ {0x02, "invalid version level"},
+ {0x03, "logical error"},
+ {0x04, "invalid CT_IU size"},
+ {0x05, "logical busy"},
+ {0x07, "protocol error"},
+ {0x09, "unable to perform command request"},
+ {0x0b, "command not supported"},
+ {0x0d, "server not available"},
+ {0x0e, "session could not be established"},
+ {0xff, "vendor specific error"},
+ {0, NULL},
+};
+
+/* LS_RJT reason codes acc. to FC-FS */
+static const struct zfcp_rc_entry zfcp_ls_rjt_rc[] = {
+ {0x01, "invalid LS_Command code"},
+ {0x03, "logical error"},
+ {0x05, "logical busy"},
+ {0x07, "protocol error"},
+ {0x09, "unable to perform command request"},
+ {0x0b, "command not supported"},
+ {0x0e, "command already in progress"},
+ {0xff, "vendor specific error"},
+ {0, NULL},
+};
+
+/* reject reason codes according to FC-PH/FC-FS */
+static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
+ {0x01, "invalid D_ID"},
+ {0x02, "invalid S_ID"},
+ {0x03, "Nx_Port not available, temporary"},
+ {0x04, "Nx_Port not available, permament"},
+ {0x05, "class not supported"},
+ {0x06, "delimiter usage error"},
+ {0x07, "TYPE not supported"},
+ {0x08, "invalid Link_Control"},
+ {0x09, "invalid R_CTL field"},
+ {0x0a, "invalid F_CTL field"},
+ {0x0b, "invalid OX_ID"},
+ {0x0c, "invalid RX_ID"},
+ {0x0d, "invalid SEQ_ID"},
+ {0x0e, "invalid DF_CTL"},
+ {0x0f, "invalid SEQ_CNT"},
+ {0x10, "invalid parameter field"},
+ {0x11, "exchange error"},
+ {0x12, "protocol error"},
+ {0x13, "incorrect length"},
+ {0x14, "unsupported ACK"},
+ {0x15, "class of service not supported by entity at FFFFFE"},
+ {0x16, "login required"},
+ {0x17, "excessive sequences attempted"},
+ {0x18, "unable to establish exchange"},
+ {0x1a, "fabric path not available"},
+ {0x1b, "invalid VC_ID (class 4)"},
+ {0x1c, "invalid CS_CTL field"},
+ {0x1d, "insufficient resources for VC (class 4)"},
+ {0x1f, "invalid class of service"},
+ {0x20, "preemption request rejected"},
+ {0x21, "preemption not enabled"},
+ {0x22, "multicast error"},
+ {0x23, "multicast error terminate"},
+ {0x24, "process login required"},
+ {0xff, "vendor specific reject"},
+ {0, NULL},
+};
+
+/**
+ * zfcp_rc_description - return description for given reaon code
+ * @code: reason code
+ * @rc_table: table of reason codes and descriptions
+ */
+static inline const char *
+zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
+{
+ const char *descr = "unknown reason code";
+
+ do {
+ if (code == rc_table->code) {
+ descr = rc_table->description;
+ break;
+ }
+ rc_table++;
+ } while (rc_table->code && rc_table->description);
+
+ return descr;
+}
+
+/**
+ * zfcp_check_ct_response - evaluate reason code for CT_IU
+ * @rjt: response payload to an CT_IU request
+ * Return: 0 for accept CT_IU, 1 for reject CT_IU or invlid response code
+ */
+int
+zfcp_check_ct_response(struct ct_hdr *rjt)
+{
+ if (rjt->cmd_rsp_code == ZFCP_CT_ACCEPT)
+ return 0;
+
+ if (rjt->cmd_rsp_code != ZFCP_CT_REJECT) {
+ ZFCP_LOG_NORMAL("error: invalid Generic Service command/"
+ "response code (0x%04hx)\n",
+ rjt->cmd_rsp_code);
+ return 1;
+ }
+
+ ZFCP_LOG_INFO("Generic Service command rejected\n");
+ ZFCP_LOG_INFO("%s (0x%02x, 0x%02x, 0x%02x)\n",
+ zfcp_rc_description(rjt->reason_code, zfcp_ct_rc),
+ (u32) rjt->reason_code, (u32) rjt->reason_code_expl,
+ (u32) rjt->vendor_unique);
+
+ return 1;
+}
+
+/**
+ * zfcp_print_els_rjt - print reject parameter and description for ELS reject
+ * @rjt_par: reject parameter acc. to FC-PH/FC-FS
+ * @rc_table: table of reason codes and descriptions
+ */
+static inline void
+zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
+ const struct zfcp_rc_entry *rc_table)
+{
+ ZFCP_LOG_INFO("%s (%02x %02x %02x %02x)\n",
+ zfcp_rc_description(rjt_par->reason_code, rc_table),
+ (u32) rjt_par->action, (u32) rjt_par->reason_code,
+ (u32) rjt_par->reason_expl, (u32) rjt_par->vendor_unique);
+}
+
+/**
+ * zfcp_fsf_handle_els_rjt - evaluate status qualifier/reason code on ELS reject
+ * @sq: status qualifier word
+ * @rjt_par: reject parameter as described in FC-PH and FC-FS
+ * Return: -EROMTEIO for LS_RJT, -EREMCHG for invalid D_ID, -EIO else
+ */
+int
+zfcp_handle_els_rjt(u32 sq, struct zfcp_ls_rjt_par *rjt_par)
+{
+ int ret = -EIO;
+
+ if (sq == FSF_IOSTAT_NPORT_RJT) {
+ ZFCP_LOG_INFO("ELS rejected (P_RJT)\n");
+ zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc);
+ /* invalid d_id */
+ if (rjt_par->reason_code == 0x01)
+ ret = -EREMCHG;
+ } else if (sq == FSF_IOSTAT_FABRIC_RJT) {
+ ZFCP_LOG_INFO("ELS rejected (F_RJT)\n");
+ zfcp_print_els_rjt(rjt_par, zfcp_p_rjt_rc);
+ /* invalid d_id */
+ if (rjt_par->reason_code == 0x01)
+ ret = -EREMCHG;
+ } else if (sq == FSF_IOSTAT_LS_RJT) {
+ ZFCP_LOG_INFO("ELS rejected (LS_RJT)\n");
+ zfcp_print_els_rjt(rjt_par, zfcp_ls_rjt_rc);
+ ret = -EREMOTEIO;
+ } else
+ ZFCP_LOG_INFO("unexpected SQ: 0x%02x\n", sq);
+
+ return ret;
+}
+
#undef ZFCP_LOG_AREA
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index dda20bf004062..7a5f2bf648132 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -33,7 +33,7 @@
#define ZFCP_DEF_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_DEF_REVISION "$Revision: 1.81 $"
+#define ZFCP_DEF_REVISION "$Revision: 1.83 $"
/*************************** INCLUDES *****************************************/
@@ -296,13 +296,11 @@ struct fcp_logo {
#define ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED 0x0B
#define ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR 0xFF
-struct zfcp_ls_rjt {
- u8 code;
- u8 field[3];
- u8 reserved;
- u8 reason_code;
- u8 reason_expl;
- u8 vendor_unique;
+struct zfcp_ls_rjt_par {
+ u8 action;
+ u8 reason_code;
+ u8 reason_expl;
+ u8 vendor_unique;
} __attribute__ ((packed));
struct zfcp_ls_rtv {
@@ -423,6 +421,11 @@ struct zfcp_ls_rnid_acc {
specific_id;
} __attribute__((packed));
+struct zfcp_rc_entry {
+ u8 code;
+ const char *description;
+};
+
/*
* FC-GS-2 stuff
*/
@@ -431,9 +434,9 @@ struct zfcp_ls_rnid_acc {
#define ZFCP_CT_NAME_SERVER 0x02
#define ZFCP_CT_SYNCHRONOUS 0x00
#define ZFCP_CT_GID_PN 0x0121
-#define ZFCP_CT_GA_NXT 0x0100
#define ZFCP_CT_MAX_SIZE 0x1020
#define ZFCP_CT_ACCEPT 0x8002
+#define ZFCP_CT_REJECT 0x8001
/*
* FC-GS-4 stuff
@@ -851,7 +854,7 @@ struct zfcp_gid_pn_data {
struct zfcp_port *port;
};
-typedef int (*zfcp_send_els_handler_t)(unsigned long);
+typedef void (*zfcp_send_els_handler_t)(unsigned long);
/* used to pass parameters to zfcp_send_els() */
/* ToDo merge send_ct() and send_els() and corresponding structs */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index e0766777e5d2f..6dc68925190db 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -31,12 +31,12 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_ERP_REVISION "$Revision: 1.61 $"
+#define ZFCP_ERP_REVISION "$Revision: 1.62 $"
#include "zfcp_ext.h"
static int zfcp_els(struct zfcp_port *, u8);
-static int zfcp_els_handler(unsigned long);
+static void zfcp_els_handler(unsigned long);
static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int);
static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int);
@@ -324,6 +324,7 @@ zfcp_els(struct zfcp_port *port, u8 ls_code)
send_els->completion = NULL;
req = zfcp_sg_to_address(send_els->req);
+ memset(req, 0, PAGE_SIZE);
*(u32*)req = 0;
*(u8*)req = ls_code;
@@ -412,185 +413,99 @@ out:
}
-/*
- * function: zfcp_els_handler
- *
- * purpose: Handler for all kind of ELSs
- *
- * returns: 0 - Operation completed successfuly
- * -ENXIO - ELS has been rejected
- * -EPERM - Port forced reopen failed
+/**
+ * zfcp_els_handler - handler for ELS commands
+ * @data: pointer to struct zfcp_send_els
+ * If ELS failed (LS_RJT or timed out) forced reopen of the port is triggered.
*/
-int
+void
zfcp_els_handler(unsigned long data)
{
struct zfcp_send_els *send_els = (struct zfcp_send_els*)data;
struct zfcp_port *port = send_els->port;
- struct zfcp_ls_rjt *rjt;
struct zfcp_ls_rtv_acc *rtv;
struct zfcp_ls_rls_acc *rls;
struct zfcp_ls_pdisc_acc *pdisc;
struct zfcp_ls_adisc_acc *adisc;
void *req, *resp;
- u8 req_code, resp_code;
- int retval = 0;
+ u8 req_code;
+ /* request rejected or timed out */
if (send_els->status != 0) {
ZFCP_LOG_NORMAL("ELS request timed out, force physical port "
"reopen of port 0x%016Lx on adapter %s\n",
port->wwpn, zfcp_get_busid_by_port(port));
debug_text_event(port->adapter->erp_dbf, 3, "forcreop");
- retval = zfcp_erp_port_forced_reopen(port, 0);
- if (retval != 0) {
+ if (zfcp_erp_port_forced_reopen(port, 0))
ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx "
"on adapter %s failed\n", port->wwpn,
zfcp_get_busid_by_port(port));
- retval = -EPERM;
- }
- goto skip_fsfstatus;
+ goto out;
}
- req = (void*)((page_to_pfn(send_els->req->page) << PAGE_SHIFT) + send_els->req->offset);
- resp = (void*)((page_to_pfn(send_els->resp->page) << PAGE_SHIFT) + send_els->resp->offset);
+ req = zfcp_sg_to_address(send_els->req);
+ resp = zfcp_sg_to_address(send_els->resp);
req_code = *(u8*)req;
- resp_code = *(u8*)resp;
-
- switch (resp_code) {
-
- case ZFCP_LS_RJT:
- rjt = (struct zfcp_ls_rjt*)resp;
-
- switch (rjt->reason_code) {
-
- case ZFCP_LS_RJT_INVALID_COMMAND_CODE:
- ZFCP_LOG_INFO("invalid LS command code "
- "(wwpn=0x%016Lx, command=0x%02x)\n",
- port->wwpn, req_code);
- break;
-
- case ZFCP_LS_RJT_LOGICAL_ERROR:
- ZFCP_LOG_INFO("logical error (wwpn=0x%016Lx, "
- "reason_expl=0x%02x)\n",
- port->wwpn, rjt->reason_expl);
- break;
-
- case ZFCP_LS_RJT_LOGICAL_BUSY:
- ZFCP_LOG_INFO("logical busy (wwpn=0x%016Lx, "
- "reason_expl=0x%02x)\n",
- port->wwpn, rjt->reason_expl);
- break;
- case ZFCP_LS_RJT_PROTOCOL_ERROR:
- ZFCP_LOG_INFO("protocol error (wwpn=0x%016Lx, "
- "reason_expl=0x%02x)\n",
- port->wwpn, rjt->reason_expl);
- break;
+ switch (req_code) {
- case ZFCP_LS_RJT_UNABLE_TO_PERFORM:
- ZFCP_LOG_INFO("unable to perform command requested "
- "(wwpn=0x%016Lx, reason_expl=0x%02x)\n",
- port->wwpn, rjt->reason_expl);
- break;
-
- case ZFCP_LS_RJT_COMMAND_NOT_SUPPORTED:
- ZFCP_LOG_INFO("command not supported (wwpn=0x%016Lx, "
- "command=0x%02x)\n",
- port->wwpn, req_code);
- break;
-
- case ZFCP_LS_RJT_VENDOR_UNIQUE_ERROR:
- ZFCP_LOG_INFO("vendor specific error (wwpn=0x%016Lx, "
- "vendor_unique=0x%02x)\n",
- port->wwpn, rjt->vendor_unique);
- break;
-
- default:
- ZFCP_LOG_NORMAL("ELS rejected by remote port 0x%016Lx "
- "on adapter %s (reason_code=0x%02x)\n",
- port->wwpn,
- zfcp_get_busid_by_port(port),
- rjt->reason_code);
- }
- retval = -ENXIO;
+ case ZFCP_LS_RTV:
+ rtv = (struct zfcp_ls_rtv_acc*)resp;
+ ZFCP_LOG_INFO("RTV response from d_id 0x%08x to s_id "
+ "0x%08x (R_A_TOV=%ds E_D_TOV=%d%cs)\n",
+ port->d_id, port->adapter->s_id,
+ rtv->r_a_tov, rtv->e_d_tov,
+ rtv->qualifier &
+ ZFCP_LS_RTV_E_D_TOV_FLAG ? 'n' : 'm');
break;
- case ZFCP_LS_ACC:
- switch (req_code) {
-
- case ZFCP_LS_RTV:
- rtv = (struct zfcp_ls_rtv_acc*)resp;
- ZFCP_LOG_INFO("RTV response from d_id 0x%08x to s_id "
- "0x%08x (R_A_TOV=%ds E_D_TOV=%d%cs)\n",
- port->d_id, port->adapter->s_id,
- rtv->r_a_tov, rtv->e_d_tov,
- rtv->qualifier &
- ZFCP_LS_RTV_E_D_TOV_FLAG ? 'n' : 'm');
- break;
-
- case ZFCP_LS_RLS:
- rls = (struct zfcp_ls_rls_acc*)resp;
- ZFCP_LOG_INFO("RLS response from d_id 0x%08x to s_id "
- "0x%08x (link_failure_count=%u, "
- "loss_of_sync_count=%u, "
- "loss_of_signal_count=%u, "
- "primitive_sequence_protocol_error=%u, "
- "invalid_transmition_word=%u, "
- "invalid_crc_count=%u)\n",
- port->d_id, port->adapter->s_id,
- rls->link_failure_count,
- rls->loss_of_sync_count,
- rls->loss_of_signal_count,
- rls->prim_seq_prot_error,
- rls->invalid_transmition_word,
- rls->invalid_crc_count);
- break;
-
- case ZFCP_LS_PDISC:
- pdisc = (struct zfcp_ls_pdisc_acc*)resp;
- ZFCP_LOG_INFO("PDISC response from d_id 0x%08x to s_id "
- "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
- "vendor='%-16s')\n", port->d_id,
- port->adapter->s_id, pdisc->wwpn,
- pdisc->wwnn, pdisc->vendor_version);
- break;
+ case ZFCP_LS_RLS:
+ rls = (struct zfcp_ls_rls_acc*)resp;
+ ZFCP_LOG_INFO("RLS response from d_id 0x%08x to s_id "
+ "0x%08x (link_failure_count=%u, "
+ "loss_of_sync_count=%u, "
+ "loss_of_signal_count=%u, "
+ "primitive_sequence_protocol_error=%u, "
+ "invalid_transmition_word=%u, "
+ "invalid_crc_count=%u)\n",
+ port->d_id, port->adapter->s_id,
+ rls->link_failure_count,
+ rls->loss_of_sync_count,
+ rls->loss_of_signal_count,
+ rls->prim_seq_prot_error,
+ rls->invalid_transmition_word,
+ rls->invalid_crc_count);
+ break;
- case ZFCP_LS_ADISC:
- adisc = (struct zfcp_ls_adisc_acc*)resp;
- ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
- "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
- "hard_nport_id=0x%08x, "
- "nport_id=0x%08x)\n", port->d_id,
- port->adapter->s_id, adisc->wwpn,
- adisc->wwnn, adisc->hard_nport_id,
- adisc->nport_id);
- /* FIXME: set wwnn in during open port */
- if (port->wwnn == 0)
- port->wwnn = adisc->wwnn;
- break;
- }
+ case ZFCP_LS_PDISC:
+ pdisc = (struct zfcp_ls_pdisc_acc*)resp;
+ ZFCP_LOG_INFO("PDISC response from d_id 0x%08x to s_id "
+ "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
+ "vendor='%-16s')\n", port->d_id,
+ port->adapter->s_id, pdisc->wwpn,
+ pdisc->wwnn, pdisc->vendor_version);
break;
- default:
- ZFCP_LOG_NORMAL("unknown payload code 0x%02x received for "
- "request 0x%02x to d_id 0x%08x, reopen needed "
- "for port 0x%016Lx on adapter %s\n", resp_code,
- req_code, port->d_id, port->wwpn,
- zfcp_get_busid_by_port(port));
- retval = zfcp_erp_port_forced_reopen(port, 0);
- if (retval != 0) {
- ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx on "
- "adapter %s failed\n", port->wwpn,
- zfcp_get_busid_by_port(port));
- retval = -EPERM;
- }
+ case ZFCP_LS_ADISC:
+ adisc = (struct zfcp_ls_adisc_acc*)resp;
+ ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
+ "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
+ "hard_nport_id=0x%08x, "
+ "nport_id=0x%08x)\n", port->d_id,
+ port->adapter->s_id, adisc->wwpn,
+ adisc->wwnn, adisc->hard_nport_id,
+ adisc->nport_id);
+ /* FIXME: set wwnn in during open port */
+ if (port->wwnn == 0)
+ port->wwnn = adisc->wwnn;
+ break;
}
-skip_fsfstatus:
+ out:
__free_pages(send_els->req->page, 0);
kfree(send_els->req);
kfree(send_els->resp);
-
- return retval;
+ kfree(send_els);
}
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index d99005c01a8d6..2cb9b983519a5 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -31,7 +31,7 @@
#ifndef ZFCP_EXT_H
#define ZFCP_EXT_H
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_EXT_REVISION "$Revision: 1.51 $"
+#define ZFCP_EXT_REVISION "$Revision: 1.53 $"
#include "zfcp_def.h"
@@ -117,9 +117,11 @@ extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management(
extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(
unsigned long, struct zfcp_adapter *, struct zfcp_unit *, int);
-/******************************** FCP ****************************************/
+/******************************* FC/FCP **************************************/
extern int zfcp_nameserver_enqueue(struct zfcp_adapter *);
extern int zfcp_ns_gid_pn_request(struct zfcp_erp_action *);
+extern int zfcp_check_ct_response(struct ct_hdr *);
+extern int zfcp_handle_els_rjt(u32, struct zfcp_ls_rjt_par *);
/******************************* SCSI ****************************************/
extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 79451af65f5e0..5e719fff7ece4 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -29,7 +29,7 @@
*/
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_FSF_C_REVISION "$Revision: 1.55 $"
+#define ZFCP_FSF_C_REVISION "$Revision: 1.59 $"
#include "zfcp_ext.h"
@@ -48,7 +48,7 @@ static int zfcp_fsf_status_read_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *);
static int zfcp_fsf_control_file_handler(struct zfcp_fsf_req *);
-static inline int zfcp_fsf_req_create_sbal_check(
+static inline int zfcp_fsf_req_sbal_check(
unsigned long *, struct zfcp_qdio_queue *, int);
static inline int zfcp_use_one_sbal(
struct scatterlist *, int, struct scatterlist *, int);
@@ -79,10 +79,9 @@ static u32 fsf_qtcb_type[] = {
};
static const char zfcp_act_subtable_type[5][8] = {
- {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
+ "unknown", "OS", "WWPN", "DID", "LUN"
};
-
/****************************************************************/
/*************** FSF related Functions *************************/
/****************************************************************/
@@ -1863,6 +1862,10 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
/* ERP strategy will escalate */
debug_text_event(adapter->erp_dbf, 1, "fsf_sq_ulp");
fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
+ retval =
+ zfcp_handle_els_rjt(header->fsf_status_qual.word[1],
+ (struct zfcp_ls_rjt_par *)
+ &header->fsf_status_qual.word[2]);
break;
case FSF_SQ_RETRY_IF_POSSIBLE:
ZFCP_LOG_FLAGS(2, "FSF_SQ_RETRY_IF_POSSIBLE\n");
@@ -1971,8 +1974,6 @@ skip_fsfstatus:
if (send_els->handler != 0)
send_els->handler(send_els->handler_data);
- kfree(send_els);
-
return retval;
}
@@ -4157,87 +4158,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
}
skip_fsfstatus:
-#if 0
- /*
- * This nasty chop at the problem is not working anymore
- * as we do not adjust the retry count anylonger in order
- * to have a number of retries that avoids I/O errors.
- * The manipulation of the retry count has been removed
- * in favour of a safe tape device handling. We must not
- * sent SCSI commands more than once to a device if no
- * retries are permitted by the high level driver. Generally
- * speaking, it was a mess to change retry counts. So it is
- * fine that this sort of workaround is gone.
- * Then, we had to face a certain number of immediate retries in case of
- * busy and queue full conditions (see below).
- * This is not acceptable
- * for the latter. Queue full conditions are used
- * by devices to indicate to a host that the host can rely
- * on the completion (or timeout) of at least one outstanding
- * command as a suggested trigger for command retries.
- * Busy conditions require a different trigger since
- * no commands are outstanding for that initiator from the
- * devices perspective.
- * The drawback of mapping a queue full condition to a
- * busy condition is the chance of wasting all retries prior
- * to the time when the device indicates that a command
- * rejected due to a queue full condition should be re-driven.
- * This case would lead to unnecessary I/O errors that
- * have to be considered fatal if for example ext3's
- * journaling would be torpedoed by such an avoidable
- * I/O error.
- * So, what issues are there with not mapping a queue-full
- * condition to a busy condition?
- * Due to the 'exclusive LUN'
- * policy enforced by the zSeries FCP channel, this
- * Linux instance is the only initiator with regard to
- * this adapter. It is safe to rely on the information
- * 'don't disturb me now ... and btw. no other commands
- * pending for you' (= queue full) sent by the LU,
- * since no other Linux can use this LUN via this adapter
- * at the same time. If there is a potential race
- * introduced by the FCP channel by not inhibiting Linux A
- * to give up a LU with commands pending while Linux B
- * grabs this LU and sends commands - thus providing
- * an exploit at the 'exclusive LUN' policy - then this
- * issue has to be considered a hardware problem. It should
- * be tracked as such if it really occurs. Even if the
- * FCP Channel spec. begs exploiters to wait for the
- * completion of all request sent to a LU prior to
- * closing this LU connection.
- * This spec. statement in conjunction with
- * the 'exclusive LUN' policy is not consistent design.
- * Another issue is how resource constraints for SCSI commands
- * might be handled by the FCP channel (just guessing for now).
- * If the FCP channel would always map resource constraints,
- * e.g. no free FC exchange ID due to I/O stress caused by
- * other sharing Linux instances, to faked queue-full
- * conditions then this would be a misinterpretation and
- * violation of SCSI standards.
- * If there are SCSI stack races as indicated below
- * then they need to be fixed just there.
- * Providing all issue above are not applicable or will
- * be fixed appropriately, removing the following hack
- * is the right thing to do.
- */
-
- /*
- * Note: This is a rather nasty chop at the problem. We cannot
- * risk adding to the mlqueue however as this will block the
- * device. If it is the last outstanding command for this host
- * it will remain blocked indefinitely. This would be quite possible
- * on the zSeries FCP adapter.
- * Also, there exists a race with scsi_insert_special relying on
- * scsi_request_fn to recalculate some command data which may not
- * happen when q->plugged is true in scsi_request_fn
- */
- if (status_byte(scpnt->result) == QUEUE_FULL) {
- ZFCP_LOG_DEBUG("Changing QUEUE_FULL to BUSY....\n");
- scpnt->result &= ~(QUEUE_FULL << 1);
- scpnt->result |= (BUSY << 1);
- }
-#endif
-
ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result);
zfcp_cmd_dbf_event_scsi("response", scpnt);
@@ -4682,8 +4602,8 @@ zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *fsf_req,
}
static inline int
-zfcp_fsf_req_create_sbal_check(unsigned long *flags,
- struct zfcp_qdio_queue *queue, int needed)
+zfcp_fsf_req_sbal_check(unsigned long *flags,
+ struct zfcp_qdio_queue *queue, int needed)
{
write_lock_irqsave(&queue->queue_lock, *flags);
if (likely(atomic_read(&queue->free_count) >= needed))
@@ -4713,29 +4633,24 @@ zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd)
* @adapter: adapter for which request queue is examined
* @req_flags: flags indicating whether to wait for needed SBAL or not
* @lock_flags: lock_flags is queue_lock is taken
- *
- * locking: on success the queue_lock for the request queue of the adapter
- * is held
+ * Return: 0 on success, otherwise -EIO, or -ERESTARTSYS
+ * Locks: lock adapter->request_queue->queue_lock on success
*/
static int
zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter, int req_flags,
unsigned long *lock_flags)
{
- int condition;
+ long ret;
struct zfcp_qdio_queue *req_queue = &adapter->request_queue;
if (unlikely(req_flags & ZFCP_WAIT_FOR_SBAL)) {
- wait_event_interruptible_timeout(adapter->request_wq,
- (condition =
- zfcp_fsf_req_create_sbal_check
- (lock_flags, req_queue, 1)),
- ZFCP_SBAL_TIMEOUT);
- if (!condition) {
- return -EIO;
- }
- } else if (!zfcp_fsf_req_create_sbal_check(lock_flags, req_queue, 1)) {
+ ret = wait_event_interruptible_timeout(adapter->request_wq,
+ zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1),
+ ZFCP_SBAL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ } else if (!zfcp_fsf_req_sbal_check(lock_flags, req_queue, 1))
return -EIO;
- }
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 8793138648721..1a4b532c73033 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -227,6 +227,10 @@
#define FSF_HBA_PORTSTATE_LINKDOWN 0x00000006
#define FSF_HBA_PORTSTATE_ERROR 0x00000007
+/* IO states of adapter */
+#define FSF_IOSTAT_NPORT_RJT 0x00000004
+#define FSF_IOSTAT_FABRIC_RJT 0x00000005
+#define FSF_IOSTAT_LS_RJT 0x00000009
struct fsf_queue_designator;
struct fsf_status_read_buffer;
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index d0a879f0a1823..cfcb296d6bb6f 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -31,7 +31,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
/* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_SCSI_REVISION "$Revision: 1.65 $"
+#define ZFCP_SCSI_REVISION "$Revision: 1.66 $"
#include "zfcp_ext.h"
@@ -430,7 +430,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
u64 dbf_fsf_req = 0;
u64 dbf_fsf_status = 0;
u64 dbf_fsf_qual[2] = { 0, 0 };
- char dbf_result[ZFCP_ABORT_DBF_LENGTH] = { "##undef" };
+ char dbf_result[ZFCP_ABORT_DBF_LENGTH] = "##undef";
memset(dbf_opcode, 0, ZFCP_ABORT_DBF_LENGTH);
memcpy(dbf_opcode,
diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c
index d7536a11afce8..25c0dce87d3a6 100644
--- a/drivers/s390/scsi/zfcp_sysfs_adapter.c
+++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c
@@ -26,18 +26,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.33 $"
+#define ZFCP_SYSFS_ADAPTER_C_REVISION "$Revision: 1.36 $"
#include "zfcp_ext.h"
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_CONFIG
static const char fc_topologies[5][25] = {
- {"<error>"},
- {"point-to-point"},
- {"fabric"},
- {"arbitrated loop"},
- {"fabric (virt. adapter)"}
+ "<error>",
+ "point-to-point",
+ "fabric",
+ "arbitrated loop",
+ "fabric (virt. adapter)"
};
/**
@@ -74,29 +74,8 @@ ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
adapter->hardware_version);
ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number);
ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no);
-
-/**
- * zfcp_sysfs_adapter_in_recovery_show - recovery state of adapter
- * @dev: pointer to belonging device
- * @buf: pointer to input buffer
- *
- * Show function of "in_recovery" attribute of adapter. Will be
- * "0" if no error recovery is pending for adapter, otherwise "1".
- */
-static ssize_t
-zfcp_sysfs_adapter_in_recovery_show(struct device *dev, char *buf)
-{
- struct zfcp_adapter *adapter;
-
- adapter = dev_get_drvdata(dev);
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status))
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(in_recovery, S_IRUGO,
- zfcp_sysfs_adapter_in_recovery_show, NULL);
+ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
+ (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
/**
* zfcp_sysfs_port_add_store - add a port to sysfs tree
@@ -138,7 +117,7 @@ zfcp_sysfs_port_add_store(struct device *dev, const char *buf, size_t count)
zfcp_port_put(port);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(port_add, S_IWUSR, NULL, zfcp_sysfs_port_add_store);
@@ -197,7 +176,7 @@ zfcp_sysfs_port_remove_store(struct device *dev, const char *buf, size_t count)
zfcp_port_dequeue(port);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store);
@@ -241,7 +220,7 @@ zfcp_sysfs_adapter_failed_store(struct device *dev,
zfcp_erp_wait(adapter);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
/**
diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c
index e0d6eecfe8828..ffd55176fb825 100644
--- a/drivers/s390/scsi/zfcp_sysfs_driver.c
+++ b/drivers/s390/scsi/zfcp_sysfs_driver.c
@@ -26,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.14 $"
+#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.15 $"
#include "zfcp_ext.h"
@@ -65,7 +65,7 @@ static ssize_t zfcp_sysfs_loglevel_##_name##_store(struct device_driver *drv, \
static ssize_t zfcp_sysfs_loglevel_##_name##_show(struct device_driver *dev, \
char *buf) \
{ \
- return sprintf(buf,"%d\n", \
+ return sprintf(buf,"%d\n", (unsigned int) \
ZFCP_GET_LOG_VALUE(ZFCP_LOG_AREA_##_define)); \
} \
\
diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c
index 11a27c1ff32ab..ccb8a03303fa8 100644
--- a/drivers/s390/scsi/zfcp_sysfs_port.c
+++ b/drivers/s390/scsi/zfcp_sysfs_port.c
@@ -26,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.41 $"
+#define ZFCP_SYSFS_PORT_C_REVISION "$Revision: 1.43 $"
#include "zfcp_ext.h"
@@ -66,6 +66,8 @@ ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status));
ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn);
ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id);
ZFCP_DEFINE_PORT_ATTR(scsi_id, "0x%x\n", port->scsi_id);
+ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask
+ (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status));
/**
* zfcp_sysfs_unit_add_store - add a unit to sysfs tree
@@ -107,7 +109,7 @@ zfcp_sysfs_unit_add_store(struct device *dev, const char *buf, size_t count)
zfcp_unit_put(unit);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(unit_add, S_IWUSR, NULL, zfcp_sysfs_unit_add_store);
@@ -164,7 +166,7 @@ zfcp_sysfs_unit_remove_store(struct device *dev, const char *buf, size_t count)
zfcp_unit_dequeue(unit);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
@@ -206,7 +208,7 @@ zfcp_sysfs_port_failed_store(struct device *dev, const char *buf, size_t count)
zfcp_erp_wait(port->adapter);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
/**
@@ -233,29 +235,6 @@ static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_port_failed_show,
zfcp_sysfs_port_failed_store);
/**
- * zfcp_sysfs_port_in_recovery_show - recovery state of port
- * @dev: pointer to belonging device
- * @buf: pointer to input buffer
- *
- * Show function of "in_recovery" attribute of port. Will be
- * "0" if no error recovery is pending for port, otherwise "1".
- */
-static ssize_t
-zfcp_sysfs_port_in_recovery_show(struct device *dev, char *buf)
-{
- struct zfcp_port *port;
-
- port = dev_get_drvdata(dev);
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status))
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_port_in_recovery_show,
- NULL);
-
-/**
* zfcp_port_common_attrs
* sysfs attributes that are common for all kind of fc ports.
*/
diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c
index 904c8aead9d61..bad3b7f2cd1bf 100644
--- a/drivers/s390/scsi/zfcp_sysfs_unit.c
+++ b/drivers/s390/scsi/zfcp_sysfs_unit.c
@@ -26,7 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.25 $"
+#define ZFCP_SYSFS_UNIT_C_REVISION "$Revision: 1.27 $"
#include "zfcp_ext.h"
@@ -64,6 +64,8 @@ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_unit_##_name##_show, NULL);
ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status));
ZFCP_DEFINE_UNIT_ATTR(scsi_lun, "0x%x\n", unit->scsi_lun);
+ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask
+ (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status));
/**
* zfcp_sysfs_unit_failed_store - failed state of unit
@@ -101,7 +103,7 @@ zfcp_sysfs_unit_failed_store(struct device *dev, const char *buf, size_t count)
zfcp_erp_wait(unit->port->adapter);
out:
up(&zfcp_data.config_sema);
- return retval ? retval : count;
+ return retval ? retval : (ssize_t) count;
}
/**
@@ -127,29 +129,6 @@ zfcp_sysfs_unit_failed_show(struct device *dev, char *buf)
static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show,
zfcp_sysfs_unit_failed_store);
-/**
- * zfcp_sysfs_unit_in_recovery_show - recovery state of unit
- * @dev: pointer to belonging device
- * @buf: pointer to input buffer
- *
- * Show function of "in_recovery" attribute of unit. Will be
- * "0" if no error recovery is pending for unit, otherwise "1".
- */
-static ssize_t
-zfcp_sysfs_unit_in_recovery_show(struct device *dev, char *buf)
-{
- struct zfcp_unit *unit;
-
- unit = dev_get_drvdata(dev);
- if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status))
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(in_recovery, S_IRUGO, zfcp_sysfs_unit_in_recovery_show,
- NULL);
-
static struct attribute *zfcp_unit_attrs[] = {
&dev_attr_scsi_lun.attr,
&dev_attr_failed.attr,
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index cba290ce97612..c402351dc79a8 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -91,10 +91,12 @@ struct chain {
};
/* These belong in scsi.h also */
-#define any2scsi(up, p) \
-(up)[0] = (((unsigned long)(p)) >> 16) ; \
-(up)[1] = (((unsigned long)(p)) >> 8); \
-(up)[2] = ((unsigned long)(p));
+static inline void any2scsi(u8 *p, u32 v)
+{
+ p[0] = v >> 16;
+ p[1] = v >> 8;
+ p[2] = v;
+}
#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
index 8778aac340631..58d140cd17e4c 100644
--- a/drivers/scsi/cpqfcTSinit.c
+++ b/drivers/scsi/cpqfcTSinit.c
@@ -302,10 +302,16 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
cpqfc_boards[i].device_id, PciDev)))
{
+ if (pci_enable_device(PciDev)) {
+ printk(KERN_ERR
+ "cpqfc: can't enable PCI device at %s\n", pci_name(PciDev));
+ goto err_continue;
+ }
+
if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
printk(KERN_WARNING
"cpqfc: HBA cannot support required DMA mask, skipping.\n");
- continue;
+ goto err_disable_dev;
}
// NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
@@ -314,8 +320,11 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
- if(HostAdapter == NULL)
- continue;
+ if(HostAdapter == NULL) {
+ printk(KERN_WARNING
+ "cpqfc: can't register SCSI HBA, skipping.\n");
+ goto err_disable_dev;
+ }
DEBUG_PCI( printk(" HBA found!\n"));
DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
DEBUG_PCI(printk(" PciDev->baseaddress[0]= %lx\n",
@@ -367,9 +376,8 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
DEV_NAME,
HostAdapter) )
{
- printk(" IRQ %u already used\n", HostAdapter->irq);
- scsi_unregister( HostAdapter);
- continue;
+ printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq);
+ goto err_unregister;
}
// Since we have two 256-byte I/O port ranges (upper
@@ -377,22 +385,17 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU,
0xff, DEV_NAME ) )
{
- printk(" cpqfcTS address in use: %x\n",
+ printk(KERN_WARNING "cpqfc: address in use: %x\n",
cpqfcHBAdata->fcChip.Registers.IOBaseU);
- free_irq( HostAdapter->irq, HostAdapter);
- scsi_unregister( HostAdapter);
- continue;
+ goto err_free_irq;
}
if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL,
0xff, DEV_NAME ) )
{
- printk(" cpqfcTS address in use: %x\n",
+ printk(KERN_WARNING "cpqfc: address in use: %x\n",
cpqfcHBAdata->fcChip.Registers.IOBaseL);
- release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
- free_irq( HostAdapter->irq, HostAdapter);
- scsi_unregister( HostAdapter);
- continue;
+ goto err_release_region_U;
}
// OK, we have grabbed everything we need now.
@@ -424,7 +427,7 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
// now initialize our hardware...
if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
- // FIXME: might want to do something better than nothing here.
+ goto err_release_region_L;
}
cpqfcHBAdata->fcStatsTime = jiffies; // (for FC Statistics delta)
@@ -455,6 +458,21 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
spin_lock_irq(HostAdapter->host_lock);
NumberOfAdapters++;
spin_unlock_irq(HostAdapter->host_lock);
+
+ continue;
+
+err_release_region_L:
+ release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff );
+err_release_region_U:
+ release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
+err_free_irq:
+ free_irq( HostAdapter->irq, HostAdapter);
+err_unregister:
+ scsi_unregister( HostAdapter);
+err_disable_dev:
+ pci_disable_device( PciDev );
+err_continue:
+ continue;
} // end of while()
}
@@ -811,6 +829,7 @@ int cpqfcTS_release(struct Scsi_Host *HostAdapter)
cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
*/
+ pci_disable_device( cpqfcHBAdata->PciDev);
LEAVE("cpqfcTS_release");
return 0;
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 6529f0c557724..a78b6f257b3df 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -733,17 +733,20 @@ static int fdomain_isa_detect( int *irq, int *iobase )
printk( " %x,", base );
#endif
- for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
- if (base == ports[i])
- ++flag;
+ for (i = 0; i < PORT_COUNT; i++) {
+ if (base == ports[i]) {
+ if (!request_region(base, 0x10, "fdomain"))
+ break;
+ if (!fdomain_is_valid_port(base)) {
+ release_region(base, 0x10);
+ break;
+ }
+ *irq = fdomain_get_irq( base );
+ *iobase = base;
+ return 1;
+ }
}
- if (flag && fdomain_is_valid_port( base )) {
- *irq = fdomain_get_irq( base );
- *iobase = base;
- return 1;
- }
-
/* This is a bad sign. It usually means that someone patched the
BIOS signature list (the signatures variable) to contain a BIOS
signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */
@@ -764,7 +767,7 @@ static int fdomain_isa_detect( int *irq, int *iobase )
for (i = 0; i < PORT_COUNT; i++) {
base = ports[i];
- if (check_region( base, 0x10 )) {
+ if (!request_region(base, 0x10, "fdomain")) {
#if DEBUG_DETECT
printk( " (%x inuse),", base );
#endif
@@ -773,7 +776,10 @@ static int fdomain_isa_detect( int *irq, int *iobase )
#if DEBUG_DETECT
printk( " %x,", base );
#endif
- if ((flag = fdomain_is_valid_port( base ))) break;
+ flag = fdomain_is_valid_port(base);
+ if (flag)
+ break;
+ release_region(base, 0x10);
}
#if DEBUG_DETECT
@@ -832,6 +838,9 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_
pci_base = pci_resource_start(pdev, 0);
pci_irq = pdev->irq;
+ if (!request_region( pci_base, 0x10, "fdomain" ))
+ return 0;
+
/* Now we have the I/O base address and interrupt from the PCI
configuration registers. */
@@ -844,8 +853,9 @@ static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_
" IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base );
#endif
- if (!fdomain_is_valid_port( *iobase )) {
+ if (!fdomain_is_valid_port(pci_base)) {
printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" );
+ release_region(pci_base, 0x10);
return 0;
}
@@ -870,10 +880,16 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
printk( "scsi: <fdomain> No BIOS, using port_base = 0x%x, irq = %d\n",
port_base, interrupt_level );
#endif
+ if (!request_region(port_base, 0x10, "fdomain")) {
+ printk( "scsi: <fdomain> port 0x%x is busy\n", port_base );
+ printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
+ return NULL;
+ }
if (!fdomain_is_valid_port( port_base )) {
printk( "scsi: <fdomain> Cannot locate chip at port base 0x%x\n",
port_base );
printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
+ release_region(port_base, 0x10);
return NULL;
}
} else {
@@ -915,6 +931,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
if (setup_called) {
printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
}
+ release_region(port_base, 0x10);
return NULL;
}
@@ -935,8 +952,10 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
get resources. */
shpnt = scsi_register( tpnt, 0 );
- if(shpnt == NULL)
+ if(shpnt == NULL) {
+ release_region(port_base, 0x10);
return NULL;
+ }
shpnt->irq = interrupt_level;
shpnt->io_port = port_base;
scsi_set_device(shpnt, &pdev->dev);
@@ -946,6 +965,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
/* Log IRQ with kernel */
if (!interrupt_level) {
printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" );
+ release_region(port_base, 0x10);
return NULL;
} else {
/* Register the IRQ with the kernel */
@@ -967,13 +987,10 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
printk(KERN_ERR " Send mail to faith@acm.org\n" );
}
printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
+ release_region(port_base, 0x10);
return NULL;
}
}
-
- /* Log I/O ports with kernel */
- request_region( port_base, 0x10, "fdomain" );
-
return shpnt;
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index e2cc4aec3e17e..d84dbfb24be20 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -182,16 +182,14 @@ static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
if (disk->private_data == NULL)
goto out;
sdkp = scsi_disk(disk);
- if (!kref_get(&sdkp->kref))
- goto out_sdkp;
+ kref_get(&sdkp->kref);
if (scsi_device_get(sdkp->device))
goto out_put;
up(&sd_ref_sem);
return sdkp;
out_put:
- kref_put(&sdkp->kref);
- out_sdkp:
+ kref_put(&sdkp->kref, scsi_disk_release);
sdkp = NULL;
out:
up(&sd_ref_sem);
@@ -202,7 +200,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
{
down(&sd_ref_sem);
scsi_device_put(sdkp->device);
- kref_put(&sdkp->kref);
+ kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem);
}
@@ -1420,7 +1418,7 @@ static int sd_probe(struct device *dev)
goto out;
memset (sdkp, 0, sizeof(*sdkp));
- kref_init(&sdkp->kref, scsi_disk_release);
+ kref_init(&sdkp->kref);
/* Note: We can accomodate 64 partitions, but the genhd code
* assumes partitions allocate consecutive minors, which they don't.
@@ -1522,7 +1520,7 @@ static int sd_remove(struct device *dev)
del_gendisk(sdkp->disk);
sd_shutdown(dev);
down(&sd_ref_sem);
- kref_put(&sdkp->kref);
+ kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem);
return 0;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index b80aa283c9212..ba2789d726337 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -140,15 +140,13 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
if (disk->private_data == NULL)
goto out;
cd = scsi_cd(disk);
- if (!kref_get(&cd->kref))
- goto out_null;
+ kref_get(&cd->kref);
if (scsi_device_get(cd->device))
goto out_put;
goto out;
out_put:
- kref_put(&cd->kref);
- out_null:
+ kref_put(&cd->kref, sr_kref_release);
cd = NULL;
out:
up(&sr_ref_sem);
@@ -159,7 +157,7 @@ static inline void scsi_cd_put(struct scsi_cd *cd)
{
down(&sr_ref_sem);
scsi_device_put(cd->device);
- kref_put(&cd->kref);
+ kref_put(&cd->kref, sr_kref_release);
up(&sr_ref_sem);
}
@@ -576,7 +574,7 @@ static int sr_probe(struct device *dev)
goto fail;
memset(cd, 0, sizeof(*cd));
- kref_init(&cd->kref, sr_kref_release);
+ kref_init(&cd->kref);
disk = alloc_disk(1);
if (!disk)
@@ -937,7 +935,7 @@ static int sr_remove(struct device *dev)
del_gendisk(cd->disk);
down(&sr_ref_sem);
- kref_put(&cd->kref);
+ kref_put(&cd->kref, sr_kref_release);
up(&sr_ref_sem);
return 0;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 193e40c187a98..553a5f1e2d99d 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -190,7 +190,6 @@
#include <scsi/scsicam.h>
-#define ANY2SCSI_INLINE /* undef this to use old macros */
#undef WD7000_DEBUG /* general debug */
#ifdef WD7000_DEBUG
#define dprintk printk
@@ -726,55 +725,17 @@ static int __init wd7000_setup(char *str)
__setup("wd7000=", wd7000_setup);
-#ifdef ANY2SCSI_INLINE
-/*
- * Since they're used a lot, I've redone the following from the macros
- * formerly in wd7000.h, hopefully to speed them up by getting rid of
- * all the shifting (it may not matter; GCC might have done as well anyway).
- *
- * xany2scsi and xscsi2int were not being used, and are no longer defined.
- * (They were simply 4-byte versions of these routines).
- */
-typedef union { /* let's cheat... */
- int i;
- unchar u[sizeof(int)]; /* the sizeof(int) makes it more portable */
-} i_u;
-
-
static inline void any2scsi(unchar * scsi, int any)
{
- *scsi++ = ((i_u) any).u[2];
- *scsi++ = ((i_u) any).u[1];
- *scsi++ = ((i_u) any).u[0];
+ *scsi++ = (unsigned)any >> 16;
+ *scsi++ = (unsigned)any >> 8;
+ *scsi++ = any;
}
-
static inline int scsi2int(unchar * scsi)
{
- i_u result;
-
- result.i = 0; /* clears unused bytes */
- result.u[2] = *scsi++;
- result.u[1] = *scsi++;
- result.u[0] = *scsi++;
-
- return (result.i);
+ return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2];
}
-#else
-/*
- * These are the old ones - I've just moved them here...
- */
-#undef any2scsi
-#define any2scsi(up, p) (up)[0] = (((unsigned long) (p)) >> 16); \
- (up)[1] = ((unsigned long) (p)) >> 8; \
- (up)[2] = ((unsigned long) (p));
-
-#undef scsi2int
-#define scsi2int(up) ( (((unsigned long) *(up)) << 16) + \
- (((unsigned long) (up)[1]) << 8) + \
- ((unsigned long) (up)[2]) )
-#endif
-
static inline void wd7000_enable_intr(Adapter * host)
{
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index 64e296ad3b608..c0a89c547dea7 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -2592,7 +2592,7 @@ int rs_360_init(void)
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
- printk(KERN_INFO "ttyS%02d at irq 0x%02x is an %s\n",
+ printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
i, (unsigned int)(state->irq),
(state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index eff63b7fcc247..65affdd944e5f 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -50,6 +50,7 @@
#include <linux/miscdevice.h>
#include <linux/serial_core.h>
+#include <asm/io.h>
#include <asm/sn/simulator.h>
#include <asm/sn/sn2/sn_private.h>
#include <asm/sn/sn_sal.h>
@@ -1086,7 +1087,9 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
spin_unlock_irqrestore(&port->sc_port.lock, flags);
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
}
+#endif
}
else {
/* Not yet registered with serial core - simple case */
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 7391ae6490294..bfcc08d3e0f66 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -706,7 +706,7 @@ int zs_startup(struct dec_serial * info)
save_flags(flags); cli();
#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%02d (irq %d)...", info->line, info->irq);
+ printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
#endif
/*
@@ -1356,7 +1356,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
}
#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttyS%02d, count = %d\n", info->line, info->count);
+ printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
#endif
if ((tty->count == 1) && (info->count != 1)) {
/*
@@ -1371,7 +1371,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
info->count = 1;
}
if (--info->count < 0) {
- printk("rs_close: bad serial port count for ttyS%02d: %d\n",
+ printk("rs_close: bad serial port count for ttyS%d: %d\n",
info->line, info->count);
info->count = 0;
}
@@ -1531,7 +1531,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttyS%02d, count = %d\n",
+ printk("block_til_ready before block: ttyS%d, count = %d\n",
info->line, info->count);
#endif
cli();
@@ -1565,7 +1565,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
break;
}
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttyS%02d, count = %d\n",
+ printk("block_til_ready blocking: ttyS%d, count = %d\n",
info->line, info->count);
#endif
schedule();
@@ -1576,7 +1576,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
info->count++;
info->blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttyS%02d, count = %d\n",
+ printk("block_til_ready after blocking: ttyS%d, count = %d\n",
info->line, info->count);
#endif
if (retval)
@@ -1742,14 +1742,10 @@ static void __init probe_sccs(void)
* We're called early and memory managment isn't up, yet.
* Thus check_region would fail.
*/
- if (check_region((unsigned long)
+ if (!request_region((unsigned long)
zs_channels[n_channels].control,
- ZS_CHAN_IO_SIZE) < 0) {
+ ZS_CHAN_IO_SIZE, "SCC"))
panic("SCC I/O region is not free");
- }
- request_region((unsigned long)
- zs_channels[n_channels].control,
- ZS_CHAN_IO_SIZE, "SCC");
#endif
zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
zs_soft[n_channels].irq = zs_parms->irq;
@@ -1896,7 +1892,7 @@ int __init zs_init(void)
info->tqueue.data = info;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
- printk("ttyS%02d at 0x%08x (irq = %d)", info->line,
+ printk("ttyS%d at 0x%08x (irq = %d)", info->line,
info->port, info->irq);
printk(" is a Z85C30 SCC\n");
tty_register_device(serial_driver, info->line, NULL);
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 1d0a2e1a7f77a..59a6515e760f5 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -7718,6 +7718,23 @@ static void __exit ixj_exit(void)
cleanup();
}
+static IXJ *new_ixj(unsigned long port)
+{
+ IXJ *res;
+ if (!request_region(port, 16, "ixj DSP")) {
+ printk(KERN_INFO "ixj: can't get I/O address 0x%lx\n", port);
+ return NULL;
+ }
+ res = ixj_alloc();
+ if (!res) {
+ release_region(port, 16);
+ printk(KERN_INFO "ixj: out of memory\n");
+ return NULL;
+ }
+ res->DSPbase = port;
+ return res;
+}
+
int __init ixj_probe_isapnp(int *cnt)
{
int probe = 0;
@@ -7750,15 +7767,9 @@ int __init ixj_probe_isapnp(int *cnt)
return -ENODEV;
}
- result = check_region(pnp_port_start(dev, 0), 16);
- if (result) {
- printk(KERN_INFO "ixj: can't get I/O address 0x%lx\n", pnp_port_start(dev, 0));
+ j = new_ixj(pnp_port_start(dev, 0));
+ if (!j)
break;
- }
-
- j = ixj_alloc();
- j->DSPbase = pnp_port_start(dev,0);
- request_region(j->DSPbase, 16, "ixj DSP");
if (func != 0x110)
j->XILINXbase = pnp_port_start(dev, 1); /* get real port */
@@ -7806,22 +7817,15 @@ int __init ixj_probe_isapnp(int *cnt)
int __init ixj_probe_isa(int *cnt)
{
- int i, result, probe;
+ int i, probe;
/* Use passed parameters for older kernels without PnP */
for (i = 0; i < IXJMAX; i++) {
if (dspio[i]) {
- IXJ *j;
+ IXJ *j = new_ixj(dspio[i]);
- if ((result = check_region(ixj[*cnt].DSPbase, 16)) < 0) {
- printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[*cnt].DSPbase);
+ if (!j)
break;
- }
-
- j = ixj_alloc();
-
- j->DSPbase = dspio[i];
- request_region(j->DSPbase, 16, "ixj DSP");
j->XILINXbase = xio[i];
j->cardtype = 0;
@@ -7840,7 +7844,6 @@ int __init ixj_probe_pci(int *cnt)
struct pci_dev *pci = NULL;
int i, probe = 0;
IXJ *j = NULL;
- int result;
for (i = 0; i < IXJMAX - *cnt; i++) {
pci = pci_find_device(0x15E2, 0x0500, pci);
@@ -7849,20 +7852,12 @@ int __init ixj_probe_pci(int *cnt)
if (pci_enable_device(pci))
break;
- if ((result = check_region(pci_resource_start(pci, 0), 16)) < 0) {
- printk(KERN_INFO "ixj: can't get I/O address\n");
+ j = new_ixj(pci_resource_start(pci, 0));
+ if (!j)
break;
- }
- /* Grab a device slot */
- j = ixj_alloc();
- if(j == NULL)
- break;
-
- j->DSPbase = pci_resource_start(pci, 0);
j->serial = (PCIEE_GetSerialNumber)pci_resource_start(pci, 2);
j->XILINXbase = j->DSPbase + 0x10;
- request_region(j->DSPbase, 16, "ixj DSP");
j->cardtype = QTI_PHONEJACK_PCI;
j->board = *cnt;
probe = ixj_selfprobe(j);
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
index ad23b28e6f7ff..143818a561211 100644
--- a/drivers/telephony/ixj.h
+++ b/drivers/telephony/ixj.h
@@ -1188,12 +1188,12 @@ typedef struct {
unsigned int cid_rec_codec;
unsigned int cid_rec_volume;
unsigned char cid_rec_flag;
- char rec_mode;
+ signed char rec_mode;
unsigned int play_codec;
unsigned int cid_play_codec;
unsigned int cid_play_volume;
unsigned char cid_play_flag;
- char play_mode;
+ signed char play_mode;
IXJ_FLAGS flags;
unsigned long busyflags;
unsigned int rec_frame_size;
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index ae7ec74052fb6..33c51714f49c0 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -106,7 +106,7 @@ skip_to_next_endpoint_or_interface_descriptor:
return buffer - buffer0 + i;
}
-static void usb_release_interface_cache(struct kref *ref)
+void usb_release_interface_cache(struct kref *ref)
{
struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
int j;
@@ -356,7 +356,7 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
if (!intfc)
return -ENOMEM;
memset(intfc, 0, len);
- kref_init(&intfc->ref, usb_release_interface_cache);
+ kref_init(&intfc->ref);
}
/* Skip over any Class Specific or Vendor Specific descriptors;
@@ -422,7 +422,8 @@ void usb_destroy_configuration(struct usb_device *dev)
for (i = 0; i < cf->desc.bNumInterfaces; i++) {
if (cf->intf_cache[i])
- kref_put(&cf->intf_cache[i]->ref);
+ kref_put(&cf->intf_cache[i]->ref,
+ usb_release_interface_cache);
}
}
kfree(dev->config);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e0f9b3af9ba59..2768a6df862db 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1196,7 +1196,7 @@ static void release_interface(struct device *dev)
struct usb_interface_cache *intfc =
altsetting_to_usb_interface_cache(intf->altsetting);
- kref_put(&intfc->ref);
+ kref_put(&intfc->ref, usb_release_interface_cache);
kfree(intf);
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 2defd6ab4ab0d..3c14361bbeb38 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -39,7 +39,7 @@ void usb_init_urb(struct urb *urb)
{
if (urb) {
memset(urb, 0, sizeof(*urb));
- kref_init(&urb->kref, urb_destroy);
+ kref_init(&urb->kref);
spin_lock_init(&urb->lock);
}
}
@@ -88,7 +88,7 @@ struct urb *usb_alloc_urb(int iso_packets, int mem_flags)
void usb_free_urb(struct urb *urb)
{
if (urb)
- kref_put(&urb->kref);
+ kref_put(&urb->kref, urb_destroy);
}
/**
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 7d978af3a0b03..f1dff4f4d5d62 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -10,6 +10,7 @@ extern int usb_unbind_interface (struct device *dev);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
+extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern void usb_enable_endpoint (struct usb_device *dev,
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index c746ecbe15826..181453efb9878 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -577,10 +577,10 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
return value;
}
-static long ep_aio_read_retry(struct kiocb *iocb)
+static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{
struct kiocb_priv *priv = (void *) &iocb->private;
- int status = priv->actual;
+ ssize_t status = priv->actual;
/* we "retry" to get the right mm context for this: */
status = copy_to_user(priv->ubuf, priv->buf, priv->actual);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 452c73ede7df5..438701e17946f 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -146,8 +146,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
#else
-#define ehci_hub_suspend 0
-#define ehci_hub_resume 0
+#define ehci_hub_suspend NULL
+#define ehci_hub_resume NULL
#endif /* CONFIG_PM */
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 31f311d53b05c..33d99d3ba6a34 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -114,7 +114,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
return qh;
memset (qh, 0, sizeof *qh);
- kref_init(&qh->kref, qh_destroy);
+ kref_init(&qh->kref);
qh->ehci = ehci;
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
@@ -139,7 +139,7 @@ static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
static inline void qh_put (struct ehci_qh *qh)
{
- kref_put(&qh->kref);
+ kref_put(&qh->kref, qh_destroy);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index c1f1c1d207649..61a42bdae1d88 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -112,11 +112,11 @@
#define ATI_INPUTNUM 1 /* Which input device to register as */
static unsigned long channel_mask = 0;
-module_param(channel_mask, ulong, 444);
+module_param(channel_mask, ulong, 0444);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
static int debug = 0;
-module_param(debug, int, 444);
+module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 6f6e4e16c472a..d248186f3a759 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1037,7 +1037,8 @@ static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs)
/* now extract the information */
channelid = cp->intbufp[2];
- bytecount = le16_to_cpup (&cp->intbufp[3]);
+ bytecount = (unsigned char)cp->intbufp[3];
+ bytecount |= (unsigned char)cp->intbufp[4] << 8;
/* check the channel id */
if (channelid >= AUH_TYPESIZE) {
@@ -1930,7 +1931,7 @@ static int auerswald_probe (struct usb_interface *intf,
struct usb_device *usbdev = interface_to_usbdev(intf);
pauerswald_t cp = NULL;
unsigned int u = 0;
- char *pbuf;
+ u16 *pbuf;
int ret;
dbg ("probe: vendor id 0x%x, device id 0x%x",
@@ -2002,7 +2003,7 @@ static int auerswald_probe (struct usb_interface *intf,
info("device is a %s", cp->dev_desc);
/* get the maximum allowed control transfer length */
- pbuf = (char *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */
+ pbuf = (u16 *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */
if (!pbuf) {
err( "out of memory");
goto pfail;
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index d9d09e9842a37..6724399513f32 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -265,7 +265,7 @@ static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
if (i < MII_TIMEOUT) {
get_registers(dev, PHYDAT, 2, data);
- *reg = le16_to_cpup(data);
+ *reg = data[0] | (data[1] << 8);
return 0;
} else
return 1;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 2656807d7c18f..0e59c134134cc 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -421,6 +421,63 @@ static void return_serial (struct usb_serial *serial)
return;
}
+static void destroy_serial(struct kref *kref)
+{
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ int i;
+
+ serial = to_usb_serial(kref);
+
+ dbg ("%s - %s", __FUNCTION__, serial->type->name);
+
+ serial->type->shutdown(serial);
+
+ /* return the minor range that this device had */
+ return_serial(serial);
+
+ for (i = 0; i < serial->num_ports; ++i)
+ serial->port[i]->open_count = 0;
+
+ /* the ports are cleaned up and released in port_release() */
+ for (i = 0; i < serial->num_ports; ++i)
+ if (serial->port[i]->dev.parent != NULL) {
+ device_unregister(&serial->port[i]->dev);
+ serial->port[i] = NULL;
+ }
+
+ /* If this is a "fake" port, we have to clean it up here, as it will
+ * not get cleaned up in port_release() as it was never registered with
+ * the driver core */
+ if (serial->num_ports < serial->num_port_pointers) {
+ for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
+ port = serial->port[i];
+ if (!port)
+ continue;
+ if (port->read_urb) {
+ usb_unlink_urb(port->read_urb);
+ usb_free_urb(port->read_urb);
+ }
+ if (port->write_urb) {
+ usb_unlink_urb(port->write_urb);
+ usb_free_urb(port->write_urb);
+ }
+ if (port->interrupt_in_urb) {
+ usb_unlink_urb(port->interrupt_in_urb);
+ usb_free_urb(port->interrupt_in_urb);
+ }
+ kfree(port->bulk_in_buffer);
+ kfree(port->bulk_out_buffer);
+ kfree(port->interrupt_in_buffer);
+ }
+ }
+
+ usb_put_dev(serial->dev);
+
+ /* free up any memory that we allocated */
+ kfree (serial);
+}
+
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
@@ -465,7 +522,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
if (retval) {
port->open_count = 0;
module_put(serial->type->owner);
- kref_put(&serial->kref);
+ kref_put(&serial->kref, destroy_serial);
}
}
bailout:
@@ -496,7 +553,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
}
module_put(port->serial->type->owner);
- kref_put(&port->serial->kref);
+ kref_put(&port->serial->kref, destroy_serial);
}
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
@@ -654,13 +711,6 @@ exit:
;
}
-static void serial_shutdown (struct usb_serial *serial)
-{
- dbg ("%s", __FUNCTION__);
-
- serial->type->shutdown(serial);
-}
-
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct usb_serial *serial;
@@ -694,7 +744,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
begin += length;
length = 0;
}
- kref_put(&serial->kref);
+ kref_put(&serial->kref, destroy_serial);
}
*eof = 1;
done:
@@ -763,62 +813,6 @@ void usb_serial_port_softint(void *private)
wake_up_interruptible(&tty->write_wait);
}
-static void destroy_serial(struct kref *kref)
-{
- struct usb_serial *serial;
- struct usb_serial_port *port;
- int i;
-
- serial = to_usb_serial(kref);
-
- dbg ("%s - %s", __FUNCTION__, serial->type->name);
- serial_shutdown (serial);
-
- /* return the minor range that this device had */
- return_serial(serial);
-
- for (i = 0; i < serial->num_ports; ++i)
- serial->port[i]->open_count = 0;
-
- /* the ports are cleaned up and released in port_release() */
- for (i = 0; i < serial->num_ports; ++i)
- if (serial->port[i]->dev.parent != NULL) {
- device_unregister(&serial->port[i]->dev);
- serial->port[i] = NULL;
- }
-
- /* If this is a "fake" port, we have to clean it up here, as it will
- * not get cleaned up in port_release() as it was never registered with
- * the driver core */
- if (serial->num_ports < serial->num_port_pointers) {
- for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- if (port->read_urb) {
- usb_unlink_urb(port->read_urb);
- usb_free_urb(port->read_urb);
- }
- if (port->write_urb) {
- usb_unlink_urb(port->write_urb);
- usb_free_urb(port->write_urb);
- }
- if (port->interrupt_in_urb) {
- usb_unlink_urb(port->interrupt_in_urb);
- usb_free_urb(port->interrupt_in_urb);
- }
- kfree(port->bulk_in_buffer);
- kfree(port->bulk_out_buffer);
- kfree(port->interrupt_in_buffer);
- }
- }
-
- usb_put_dev(serial->dev);
-
- /* free up any memory that we allocated */
- kfree (serial);
-}
-
static void port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -859,7 +853,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
serial->interface = interface;
serial->vendor = dev->descriptor.idVendor;
serial->product = dev->descriptor.idProduct;
- kref_init(&serial->kref, destroy_serial);
+ kref_init(&serial->kref);
return serial;
}
@@ -1209,7 +1203,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (serial) {
/* let the last holder of this object
* cause it to be cleaned up */
- kref_put(&serial->kref);
+ kref_put(&serial->kref, destroy_serial);
}
dev_info(dev, "device disconnected\n");
}
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index f2f65353d5ceb..85e796b70000c 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -43,7 +43,7 @@ config VIDEO_SELECT
about the Video mode selection support. If unsure, say N.
config MDA_CONSOLE
- depends on !M68K
+ depends on !M68K && ISA
tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
---help---
Say Y here if you have an old MDA or monochrome Hercules graphics
diff --git a/fs/Makefile b/fs/Makefile
index 41cac35d1b159..e68e9f5bd789a 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -91,3 +91,5 @@ obj-$(CONFIG_JFS_FS) += jfs/
obj-$(CONFIG_XFS_FS) += xfs/
obj-$(CONFIG_AFS_FS) += afs/
obj-$(CONFIG_BEFS_FS) += befs/
+obj-$(CONFIG_HOSTFS) += hostfs/
+obj-$(CONFIG_HPPFS) += hppfs/
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index e9462e76ac4cd..2f3b18e23a97d 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -241,7 +241,7 @@ static int init_inodecache(void)
{
adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
sizeof(struct adfs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (adfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index f4ebbd27ef1bf..a0358130f498a 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -115,7 +115,7 @@ static int init_inodecache(void)
{
affs_inode_cachep = kmem_cache_create("affs_inode_cache",
sizeof(struct affs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (affs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/aio.c b/fs/aio.c
index c937114d90454..0cd2c6a10e734 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -39,6 +39,9 @@
#define dprintk(x...) do { ; } while (0)
#endif
+long aio_run = 0; /* for testing only */
+long aio_wakeups = 0; /* for testing only */
+
/*------ sysctl variables----*/
atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */
unsigned aio_max_nr = 0x10000; /* system wide maximum number of aio requests */
@@ -277,6 +280,7 @@ static void aio_cancel_all(struct kioctx *ctx)
struct kiocb *iocb = list_kiocb(pos);
list_del_init(&iocb->ki_list);
cancel = iocb->ki_cancel;
+ kiocbSetCancelled(iocb);
if (cancel) {
iocb->ki_users++;
spin_unlock_irq(&ctx->ctx_lock);
@@ -337,6 +341,11 @@ void fastcall exit_aio(struct mm_struct *mm)
aio_cancel_all(ctx);
wait_for_all_aios(ctx);
+ /*
+ * this is an overkill, but ensures we don't leave
+ * the ctx on the aio_wq
+ */
+ flush_workqueue(aio_wq);
if (1 != atomic_read(&ctx->users))
printk(KERN_DEBUG
@@ -359,6 +368,8 @@ void fastcall __put_ioctx(struct kioctx *ctx)
if (unlikely(ctx->reqs_active))
BUG();
+ cancel_delayed_work(&ctx->wq);
+ flush_workqueue(aio_wq);
aio_free_ring(ctx);
mmdrop(ctx->mm);
ctx->mm = NULL;
@@ -398,6 +409,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
req->ki_obj.user = NULL;
req->ki_dtor = NULL;
req->private = NULL;
+ INIT_LIST_HEAD(&req->ki_run_list);
/* Check if the completion queue has enough free space to
* accept an event from this io.
@@ -543,85 +555,367 @@ struct kioctx *lookup_ioctx(unsigned long ctx_id)
return ioctx;
}
+/*
+ * use_mm
+ * Makes the calling kernel thread take on the specified
+ * mm context.
+ * Called by the retry thread execute retries within the
+ * iocb issuer's mm context, so that copy_from/to_user
+ * operations work seamlessly for aio.
+ * (Note: this routine is intended to be called only
+ * from a kernel thread context)
+ */
static void use_mm(struct mm_struct *mm)
{
struct mm_struct *active_mm;
+ struct task_struct *tsk = current;
+ task_lock(tsk);
+ active_mm = tsk->active_mm;
atomic_inc(&mm->mm_count);
- task_lock(current);
- active_mm = current->active_mm;
- current->mm = mm;
- if (mm != active_mm) {
- current->active_mm = mm;
- activate_mm(active_mm, mm);
- }
- task_unlock(current);
+ tsk->mm = mm;
+ tsk->active_mm = mm;
+ activate_mm(active_mm, mm);
+ task_unlock(tsk);
+
mmdrop(active_mm);
}
-static void unuse_mm(struct mm_struct *mm)
+/*
+ * unuse_mm
+ * Reverses the effect of use_mm, i.e. releases the
+ * specified mm context which was earlier taken on
+ * by the calling kernel thread
+ * (Note: this routine is intended to be called only
+ * from a kernel thread context)
+ *
+ * Comments: Called with ctx->ctx_lock held. This nests
+ * task_lock instead ctx_lock.
+ */
+void unuse_mm(struct mm_struct *mm)
{
- task_lock(current);
- current->mm = NULL;
- task_unlock(current);
+ struct task_struct *tsk = current;
+
+ task_lock(tsk);
+ tsk->mm = NULL;
/* active_mm is still 'mm' */
- enter_lazy_tlb(mm, current);
+ enter_lazy_tlb(mm, tsk);
+ task_unlock(tsk);
}
-/* Run on kevent's context. FIXME: needs to be per-cpu and warn if an
- * operation blocks.
+/*
+ * Queue up a kiocb to be retried. Assumes that the kiocb
+ * has already been marked as kicked, and places it on
+ * the retry run list for the corresponding ioctx, if it
+ * isn't already queued. Returns 1 if it actually queued
+ * the kiocb (to tell the caller to activate the work
+ * queue to process it), or 0, if it found that it was
+ * already queued.
+ *
+ * Should be called with the spin lock iocb->ki_ctx->ctx_lock
+ * held
*/
-static void aio_kick_handler(void *data)
+static inline int __queue_kicked_iocb(struct kiocb *iocb)
{
- struct kioctx *ctx = data;
+ struct kioctx *ctx = iocb->ki_ctx;
- use_mm(ctx->mm);
+ if (list_empty(&iocb->ki_run_list)) {
+ list_add_tail(&iocb->ki_run_list,
+ &ctx->run_list);
+ iocb->ki_queued++;
+ return 1;
+ }
+ return 0;
+}
- spin_lock_irq(&ctx->ctx_lock);
- while (!list_empty(&ctx->run_list)) {
- struct kiocb *iocb;
- long ret;
+/* aio_run_iocb
+ * This is the core aio execution routine. It is
+ * invoked both for initial i/o submission and
+ * subsequent retries via the aio_kick_handler.
+ * Expects to be invoked with iocb->ki_ctx->lock
+ * already held. The lock is released and reaquired
+ * as needed during processing.
+ *
+ * Calls the iocb retry method (already setup for the
+ * iocb on initial submission) for operation specific
+ * handling, but takes care of most of common retry
+ * execution details for a given iocb. The retry method
+ * needs to be non-blocking as far as possible, to avoid
+ * holding up other iocbs waiting to be serviced by the
+ * retry kernel thread.
+ *
+ * The trickier parts in this code have to do with
+ * ensuring that only one retry instance is in progress
+ * for a given iocb at any time. Providing that guarantee
+ * simplifies the coding of individual aio operations as
+ * it avoids various potential races.
+ */
+static ssize_t aio_run_iocb(struct kiocb *iocb)
+{
+ struct kioctx *ctx = iocb->ki_ctx;
+ ssize_t (*retry)(struct kiocb *);
+ ssize_t ret;
- iocb = list_entry(ctx->run_list.next, struct kiocb,
- ki_run_list);
- list_del(&iocb->ki_run_list);
- iocb->ki_users ++;
- spin_unlock_irq(&ctx->ctx_lock);
+ if (iocb->ki_retried++ > 1024*1024) {
+ printk("Maximal retry count. Bytes done %Zd\n",
+ iocb->ki_nbytes - iocb->ki_left);
+ return -EAGAIN;
+ }
- kiocbClearKicked(iocb);
- ret = iocb->ki_retry(iocb);
- if (-EIOCBQUEUED != ret) {
+ if (!(iocb->ki_retried & 0xff)) {
+ pr_debug("%ld retry: %d of %d (kick %ld, Q %ld run %ld, wake %ld)\n",
+ iocb->ki_retried,
+ iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
+ iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
+ }
+
+ if (!(retry = iocb->ki_retry)) {
+ printk("aio_run_iocb: iocb->ki_retry = NULL\n");
+ return 0;
+ }
+
+ /*
+ * We don't want the next retry iteration for this
+ * operation to start until this one has returned and
+ * updated the iocb state. However, wait_queue functions
+ * can trigger a kick_iocb from interrupt context in the
+ * meantime, indicating that data is available for the next
+ * iteration. We want to remember that and enable the
+ * next retry iteration _after_ we are through with
+ * this one.
+ *
+ * So, in order to be able to register a "kick", but
+ * prevent it from being queued now, we clear the kick
+ * flag, but make the kick code *think* that the iocb is
+ * still on the run list until we are actually done.
+ * When we are done with this iteration, we check if
+ * the iocb was kicked in the meantime and if so, queue
+ * it up afresh.
+ */
+
+ kiocbClearKicked(iocb);
+
+ /*
+ * This is so that aio_complete knows it doesn't need to
+ * pull the iocb off the run list (We can't just call
+ * INIT_LIST_HEAD because we don't want a kick_iocb to
+ * queue this on the run list yet)
+ */
+ iocb->ki_run_list.next = iocb->ki_run_list.prev = NULL;
+ spin_unlock_irq(&ctx->ctx_lock);
+
+ /* Quit retrying if the i/o has been cancelled */
+ if (kiocbIsCancelled(iocb)) {
+ ret = -EINTR;
+ aio_complete(iocb, ret, 0);
+ /* must not access the iocb after this */
+ goto out;
+ }
+
+ /*
+ * Now we are all set to call the retry method in async
+ * context. By setting this thread's io_wait context
+ * to point to the wait queue entry inside the currently
+ * running iocb for the duration of the retry, we ensure
+ * that async notification wakeups are queued by the
+ * operation instead of blocking waits, and when notified,
+ * cause the iocb to be kicked for continuation (through
+ * the aio_wake_function callback).
+ */
+ BUG_ON(current->io_wait != NULL);
+ current->io_wait = &iocb->ki_wait;
+ ret = retry(iocb);
+ current->io_wait = NULL;
+
+ if (-EIOCBRETRY != ret) {
+ if (-EIOCBQUEUED != ret) {
+ BUG_ON(!list_empty(&iocb->ki_wait.task_list));
aio_complete(iocb, ret, 0);
- iocb = NULL;
+ /* must not access the iocb after this */
}
+ } else {
+ /*
+ * Issue an additional retry to avoid waiting forever if
+ * no waits were queued (e.g. in case of a short read).
+ */
+ if (list_empty(&iocb->ki_wait.task_list))
+ kiocbSetKicked(iocb);
+ }
+out:
+ spin_lock_irq(&ctx->ctx_lock);
- spin_lock_irq(&ctx->ctx_lock);
- if (NULL != iocb)
- __aio_put_req(ctx, iocb);
+ if (-EIOCBRETRY == ret) {
+ /*
+ * OK, now that we are done with this iteration
+ * and know that there is more left to go,
+ * this is where we let go so that a subsequent
+ * "kick" can start the next iteration
+ */
+
+ /* will make __queue_kicked_iocb succeed from here on */
+ INIT_LIST_HEAD(&iocb->ki_run_list);
+ /* we must queue the next iteration ourselves, if it
+ * has already been kicked */
+ if (kiocbIsKicked(iocb)) {
+ __queue_kicked_iocb(iocb);
+ }
}
+ return ret;
+}
+
+/*
+ * __aio_run_iocbs:
+ * Process all pending retries queued on the ioctx
+ * run list.
+ * Assumes it is operating within the aio issuer's mm
+ * context. Expects to be called with ctx->ctx_lock held
+ */
+static int __aio_run_iocbs(struct kioctx *ctx)
+{
+ struct kiocb *iocb;
+ int count = 0;
+ LIST_HEAD(run_list);
+
+ list_splice_init(&ctx->run_list, &run_list);
+ while (!list_empty(&run_list)) {
+ iocb = list_entry(run_list.next, struct kiocb,
+ ki_run_list);
+ list_del(&iocb->ki_run_list);
+ /*
+ * Hold an extra reference while retrying i/o.
+ */
+ iocb->ki_users++; /* grab extra reference */
+ aio_run_iocb(iocb);
+ if (__aio_put_req(ctx, iocb)) /* drop extra ref */
+ put_ioctx(ctx);
+ count++;
+ }
+ aio_run++;
+ if (!list_empty(&ctx->run_list))
+ return 1;
+ return 0;
+}
+
+static void aio_queue_work(struct kioctx * ctx)
+{
+ unsigned long timeout;
+ /*
+ * if someone is waiting, get the work started right
+ * away, otherwise, use a longer delay
+ */
+ smp_mb();
+ if (waitqueue_active(&ctx->wait))
+ timeout = 1;
+ else
+ timeout = HZ/10;
+ queue_delayed_work(aio_wq, &ctx->wq, timeout);
+}
+
+
+/*
+ * aio_run_iocbs:
+ * Process all pending retries queued on the ioctx
+ * run list.
+ * Assumes it is operating within the aio issuer's mm
+ * context.
+ */
+static inline void aio_run_iocbs(struct kioctx *ctx)
+{
+ int requeue;
+
+ spin_lock_irq(&ctx->ctx_lock);
+
+ requeue = __aio_run_iocbs(ctx);
spin_unlock_irq(&ctx->ctx_lock);
+ if (requeue)
+ aio_queue_work(ctx);
+}
- unuse_mm(ctx->mm);
+/*
+ * just like aio_run_iocbs, but keeps running them until
+ * the list stays empty
+ */
+static inline void aio_run_all_iocbs(struct kioctx *ctx)
+{
+ spin_lock_irq(&ctx->ctx_lock);
+ while (__aio_run_iocbs(ctx))
+ ;
+ spin_unlock_irq(&ctx->ctx_lock);
}
-void fastcall kick_iocb(struct kiocb *iocb)
+/*
+ * aio_kick_handler:
+ * Work queue handler triggered to process pending
+ * retries on an ioctx. Takes on the aio issuer's
+ * mm context before running the iocbs, so that
+ * copy_xxx_user operates on the issuer's address
+ * space.
+ * Run on aiod's context.
+ */
+static void aio_kick_handler(void *data)
{
- struct kioctx *ctx = iocb->ki_ctx;
+ struct kioctx *ctx = data;
+ mm_segment_t oldfs = get_fs();
+ int requeue;
+ set_fs(USER_DS);
+ use_mm(ctx->mm);
+ spin_lock_irq(&ctx->ctx_lock);
+ requeue =__aio_run_iocbs(ctx);
+ unuse_mm(ctx->mm);
+ spin_unlock_irq(&ctx->ctx_lock);
+ set_fs(oldfs);
+ /*
+ * we're in a worker thread already, don't use queue_delayed_work,
+ */
+ if (requeue)
+ queue_work(aio_wq, &ctx->wq);
+}
+
+
+/*
+ * Called by kick_iocb to queue the kiocb for retry
+ * and if required activate the aio work queue to process
+ * it
+ */
+void queue_kicked_iocb(struct kiocb *iocb)
+{
+ struct kioctx *ctx = iocb->ki_ctx;
+ unsigned long flags;
+ int run = 0;
+
+ WARN_ON((!list_empty(&iocb->ki_wait.task_list)));
+
+ spin_lock_irqsave(&ctx->ctx_lock, flags);
+ run = __queue_kicked_iocb(iocb);
+ spin_unlock_irqrestore(&ctx->ctx_lock, flags);
+ if (run) {
+ aio_queue_work(ctx);
+ aio_wakeups++;
+ }
+}
+
+/*
+ * kick_iocb:
+ * Called typically from a wait queue callback context
+ * (aio_wake_function) to trigger a retry of the iocb.
+ * The retry is usually executed by aio workqueue
+ * threads (See aio_kick_handler).
+ */
+void fastcall kick_iocb(struct kiocb *iocb)
+{
/* sync iocbs are easy: they can only ever be executing from a
* single context. */
if (is_sync_kiocb(iocb)) {
kiocbSetKicked(iocb);
- wake_up_process(iocb->ki_obj.tsk);
+ wake_up_process(iocb->ki_obj.tsk);
return;
}
+ iocb->ki_kicked++;
+ /* If its already kicked we shouldn't queue it again */
if (!kiocbTryKick(iocb)) {
- unsigned long flags;
- spin_lock_irqsave(&ctx->ctx_lock, flags);
- list_add_tail(&iocb->ki_run_list, &ctx->run_list);
- spin_unlock_irqrestore(&ctx->ctx_lock, flags);
- queue_work(aio_wq, &ctx->wq);
+ queue_kicked_iocb(iocb);
}
}
EXPORT_SYMBOL(kick_iocb);
@@ -675,6 +969,16 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
*/
spin_lock_irqsave(&ctx->ctx_lock, flags);
+ if (iocb->ki_run_list.prev && !list_empty(&iocb->ki_run_list))
+ list_del_init(&iocb->ki_run_list);
+
+ /*
+ * cancelled requests don't get events, userland was given one
+ * when the event got cancelled.
+ */
+ if (kiocbIsCancelled(iocb))
+ goto put_rq;
+
ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
tail = info->tail;
@@ -703,6 +1007,11 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
pr_debug("added to ring %p at [%lu]\n", iocb, tail);
+ pr_debug("%ld retries: %d of %d (kicked %ld, Q %ld run %ld wake %ld)\n",
+ iocb->ki_retried,
+ iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes,
+ iocb->ki_kicked, iocb->ki_queued, aio_run, aio_wakeups);
+put_rq:
/* everything turned out well, dispose of the aiocb. */
ret = __aio_put_req(ctx, iocb);
@@ -809,13 +1118,15 @@ static int read_events(struct kioctx *ctx,
int i = 0;
struct io_event ent;
struct aio_timeout to;
+ int event_loop = 0; /* testing only */
+ int retry = 0;
/* needed to zero any padding within an entry (there shouldn't be
* any, but C is fun!
*/
memset(&ent, 0, sizeof(ent));
+retry:
ret = 0;
-
while (likely(i < nr)) {
ret = aio_read_evt(ctx, &ent);
if (unlikely(ret <= 0))
@@ -844,6 +1155,13 @@ static int read_events(struct kioctx *ctx,
/* End fast path */
+ /* racey check, but it gets redone */
+ if (!retry && unlikely(!list_empty(&ctx->run_list))) {
+ retry = 1;
+ aio_run_all_iocbs(ctx);
+ goto retry;
+ }
+
init_timeout(&to);
if (timeout) {
struct timespec ts;
@@ -858,7 +1176,6 @@ static int read_events(struct kioctx *ctx,
add_wait_queue_exclusive(&ctx->wait, &wait);
do {
set_task_state(tsk, TASK_INTERRUPTIBLE);
-
ret = aio_read_evt(ctx, &ent);
if (ret)
break;
@@ -868,6 +1185,7 @@ static int read_events(struct kioctx *ctx,
if (to.timed_out) /* Only check after read evt */
break;
schedule();
+ event_loop++;
if (signal_pending(tsk)) {
ret = -EINTR;
break;
@@ -895,6 +1213,9 @@ static int read_events(struct kioctx *ctx,
if (timeout)
clear_timeout(&to);
out:
+ pr_debug("event loop executed %d times\n", event_loop);
+ pr_debug("aio_run %ld\n", aio_run);
+ pr_debug("aio_wakeups %ld\n", aio_wakeups);
return i ? i : ret;
}
@@ -962,7 +1283,7 @@ asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp)
ret = put_user(ioctx->user_id, ctxp);
if (!ret)
return 0;
- get_ioctx(ioctx);
+
io_destroy(ioctx);
}
@@ -987,13 +1308,181 @@ asmlinkage long sys_io_destroy(aio_context_t ctx)
return -EINVAL;
}
+/*
+ * Default retry method for aio_read (also used for first time submit)
+ * Responsible for updating iocb state as retries progress
+ */
+static ssize_t aio_pread(struct kiocb *iocb)
+{
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ ssize_t ret = 0;
+
+ ret = file->f_op->aio_read(iocb, iocb->ki_buf,
+ iocb->ki_left, iocb->ki_pos);
+
+ /*
+ * Can't just depend on iocb->ki_left to determine
+ * whether we are done. This may have been a short read.
+ */
+ if (ret > 0) {
+ iocb->ki_buf += ret;
+ iocb->ki_left -= ret;
+ /*
+ * For pipes and sockets we return once we have
+ * some data; for regular files we retry till we
+ * complete the entire read or find that we can't
+ * read any more data (e.g short reads).
+ */
+ if (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode))
+ ret = -EIOCBRETRY;
+ }
+
+ /* This means we must have transferred all that we could */
+ /* No need to retry anymore */
+ if ((ret == 0) || (iocb->ki_left == 0))
+ ret = iocb->ki_nbytes - iocb->ki_left;
+
+ return ret;
+}
+
+/*
+ * Default retry method for aio_write (also used for first time submit)
+ * Responsible for updating iocb state as retries progress
+ */
+static ssize_t aio_pwrite(struct kiocb *iocb)
+{
+ struct file *file = iocb->ki_filp;
+ ssize_t ret = 0;
+
+ ret = file->f_op->aio_write(iocb, iocb->ki_buf,
+ iocb->ki_left, iocb->ki_pos);
+
+ if (ret > 0) {
+ iocb->ki_buf += ret;
+ iocb->ki_left -= ret;
+
+ ret = -EIOCBRETRY;
+ }
+
+ /* This means we must have transferred all that we could */
+ /* No need to retry anymore */
+ if ((ret == 0) || (iocb->ki_left == 0))
+ ret = iocb->ki_nbytes - iocb->ki_left;
+
+ return ret;
+}
+
+static ssize_t aio_fdsync(struct kiocb *iocb)
+{
+ struct file *file = iocb->ki_filp;
+ ssize_t ret = -EINVAL;
+
+ if (file->f_op->aio_fsync)
+ ret = file->f_op->aio_fsync(iocb, 1);
+ return ret;
+}
+
+static ssize_t aio_fsync(struct kiocb *iocb)
+{
+ struct file *file = iocb->ki_filp;
+ ssize_t ret = -EINVAL;
+
+ if (file->f_op->aio_fsync)
+ ret = file->f_op->aio_fsync(iocb, 0);
+ return ret;
+}
+
+/*
+ * aio_setup_iocb:
+ * Performs the initial checks and aio retry method
+ * setup for the kiocb at the time of io submission.
+ */
+ssize_t aio_setup_iocb(struct kiocb *kiocb)
+{
+ struct file *file = kiocb->ki_filp;
+ ssize_t ret = 0;
+
+ switch (kiocb->ki_opcode) {
+ case IOCB_CMD_PREAD:
+ ret = -EBADF;
+ if (unlikely(!(file->f_mode & FMODE_READ)))
+ break;
+ ret = -EFAULT;
+ if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf,
+ kiocb->ki_left)))
+ break;
+ ret = -EINVAL;
+ if (file->f_op->aio_read)
+ kiocb->ki_retry = aio_pread;
+ break;
+ case IOCB_CMD_PWRITE:
+ ret = -EBADF;
+ if (unlikely(!(file->f_mode & FMODE_WRITE)))
+ break;
+ ret = -EFAULT;
+ if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf,
+ kiocb->ki_left)))
+ break;
+ ret = -EINVAL;
+ if (file->f_op->aio_write)
+ kiocb->ki_retry = aio_pwrite;
+ break;
+ case IOCB_CMD_FDSYNC:
+ ret = -EINVAL;
+ if (file->f_op->aio_fsync)
+ kiocb->ki_retry = aio_fdsync;
+ break;
+ case IOCB_CMD_FSYNC:
+ ret = -EINVAL;
+ if (file->f_op->aio_fsync)
+ kiocb->ki_retry = aio_fsync;
+ break;
+ default:
+ dprintk("EINVAL: io_submit: no operation provided\n");
+ ret = -EINVAL;
+ }
+
+ if (!kiocb->ki_retry)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * aio_wake_function:
+ * wait queue callback function for aio notification,
+ * Simply triggers a retry of the operation via kick_iocb.
+ *
+ * This callback is specified in the wait queue entry in
+ * a kiocb (current->io_wait points to this wait queue
+ * entry when an aio operation executes; it is used
+ * instead of a synchronous wait when an i/o blocking
+ * condition is encountered during aio).
+ *
+ * Note:
+ * This routine is executed with the wait queue lock held.
+ * Since kick_iocb acquires iocb->ctx->ctx_lock, it nests
+ * the ioctx lock inside the wait queue lock. This is safe
+ * because this callback isn't used for wait queues which
+ * are nested inside ioctx lock (i.e. ctx->wait)
+ */
+int aio_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait);
+
+ list_del_init(&wait->task_list);
+ kick_iocb(iocb);
+ return 1;
+}
+
int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
struct iocb *iocb)
{
struct kiocb *req;
struct file *file;
ssize_t ret;
- char __user *buf;
/* enforce forwards compatibility on users */
if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
@@ -1034,58 +1523,31 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
req->ki_user_data = iocb->aio_data;
req->ki_pos = iocb->aio_offset;
- buf = (char __user *)(unsigned long)iocb->aio_buf;
+ req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf;
+ req->ki_left = req->ki_nbytes = iocb->aio_nbytes;
+ req->ki_opcode = iocb->aio_lio_opcode;
+ init_waitqueue_func_entry(&req->ki_wait, aio_wake_function);
+ INIT_LIST_HEAD(&req->ki_wait.task_list);
+ req->ki_run_list.next = req->ki_run_list.prev = NULL;
+ req->ki_retry = NULL;
+ req->ki_retried = 0;
+ req->ki_kicked = 0;
+ req->ki_queued = 0;
+ aio_run = 0;
+ aio_wakeups = 0;
- switch (iocb->aio_lio_opcode) {
- case IOCB_CMD_PREAD:
- ret = -EBADF;
- if (unlikely(!(file->f_mode & FMODE_READ)))
- goto out_put_req;
- ret = -EFAULT;
- if (unlikely(!access_ok(VERIFY_WRITE, buf, iocb->aio_nbytes)))
- goto out_put_req;
- ret = security_file_permission (file, MAY_READ);
- if (ret)
- goto out_put_req;
- ret = -EINVAL;
- if (file->f_op->aio_read)
- ret = file->f_op->aio_read(req, buf,
- iocb->aio_nbytes, req->ki_pos);
- break;
- case IOCB_CMD_PWRITE:
- ret = -EBADF;
- if (unlikely(!(file->f_mode & FMODE_WRITE)))
- goto out_put_req;
- ret = -EFAULT;
- if (unlikely(!access_ok(VERIFY_READ, buf, iocb->aio_nbytes)))
- goto out_put_req;
- ret = security_file_permission (file, MAY_WRITE);
- if (ret)
- goto out_put_req;
- ret = -EINVAL;
- if (file->f_op->aio_write)
- ret = file->f_op->aio_write(req, buf,
- iocb->aio_nbytes, req->ki_pos);
- break;
- case IOCB_CMD_FDSYNC:
- ret = -EINVAL;
- if (file->f_op->aio_fsync)
- ret = file->f_op->aio_fsync(req, 1);
- break;
- case IOCB_CMD_FSYNC:
- ret = -EINVAL;
- if (file->f_op->aio_fsync)
- ret = file->f_op->aio_fsync(req, 0);
- break;
- default:
- dprintk("EINVAL: io_submit: no operation provided\n");
- ret = -EINVAL;
- }
+ ret = aio_setup_iocb(req);
+ if (ret)
+ goto out_put_req;
+
+ spin_lock_irq(&ctx->ctx_lock);
+ list_add_tail(&req->ki_run_list, &ctx->run_list);
+ /* drain the run list */
+ while (__aio_run_iocbs(ctx))
+ ;
+ spin_unlock_irq(&ctx->ctx_lock);
aio_put_req(req); /* drop extra ref to req */
- if (likely(-EIOCBQUEUED == ret))
- return 0;
- aio_complete(req, ret, 0); /* will drop i/o ref to req */
return 0;
out_put_req:
@@ -1201,6 +1663,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,
if (kiocb && kiocb->ki_cancel) {
cancel = kiocb->ki_cancel;
kiocb->ki_users ++;
+ kiocbSetCancelled(kiocb);
} else
cancel = NULL;
spin_unlock_irq(&ctx->ctx_lock);
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 49cf3428d5113..84e932ecda711 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -433,7 +433,7 @@ befs_init_inodecache(void)
{
befs_inode_cachep = kmem_cache_create("befs_inode_cache",
sizeof (struct befs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (befs_inode_cachep == NULL) {
printk(KERN_ERR "befs_init_inodecache: "
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 9ef5b3146f2c6..b163efd7a2708 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -245,7 +245,7 @@ static int init_inodecache(void)
{
bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
sizeof(struct bfs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (bfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 77d1e681d7fa7..3d99e70d205a5 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -307,7 +307,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(current->mm->start_data = N_DATADDR(ex));
current->mm->brk = ex.a_bss +
(current->mm->start_brk = N_BSSADDR(ex));
- current->mm->free_area_cache = TASK_UNMAPPED_BASE;
+ current->mm->free_area_cache = current->mm->mmap_base;
current->mm->rss = 0;
current->mm->mmap = NULL;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index cb4f79e5bd57b..b7c6e3917afe3 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -703,10 +703,12 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_read_implies_exec(elf_ex, have_pt_gnu_stack))
current->personality |= READ_IMPLIES_EXEC;
+ arch_pick_mmap_layout(current->mm);
+
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->rss = 0;
- current->mm->free_area_cache = TASK_UNMAPPED_BASE;
+ current->mm->free_area_cache = current->mm->mmap_base;
retval = setup_arg_pages(bprm, executable_stack);
if (retval < 0) {
send_sig(SIGKILL, current, 0);
diff --git a/fs/bio.c b/fs/bio.c
index e246f542aa062..d6f2eb6607d2a 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -388,20 +388,17 @@ int bio_uncopy_user(struct bio *bio)
struct bio_vec *bvec;
int i, ret = 0;
- if (bio_data_dir(bio) == READ) {
- char *uaddr = bio->bi_private;
+ char *uaddr = bio->bi_private;
- __bio_for_each_segment(bvec, bio, i, 0) {
- char *addr = page_address(bvec->bv_page);
-
- if (!ret && copy_to_user(uaddr, addr, bvec->bv_len))
- ret = -EFAULT;
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ char *addr = page_address(bvec->bv_page);
+ if (bio_data_dir(bio) == READ && !ret &&
+ copy_to_user(uaddr, addr, bvec->bv_len))
+ ret = -EFAULT;
- __free_page(bvec->bv_page);
- uaddr += bvec->bv_len;
- }
+ __free_page(bvec->bv_page);
+ uaddr += bvec->bv_len;
}
-
bio_put(bio);
return ret;
}
@@ -457,6 +454,7 @@ struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr,
*/
if (!ret) {
if (!write_to_vm) {
+ unsigned long p = uaddr;
bio->bi_rw |= (1 << BIO_RW);
/*
* for a write, copy in data to kernel pages
@@ -465,8 +463,9 @@ struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr,
bio_for_each_segment(bvec, bio, i) {
char *addr = page_address(bvec->bv_page);
- if (copy_from_user(addr, (char *) uaddr, bvec->bv_len))
+ if (copy_from_user(addr, (char *) p, bvec->bv_len))
goto cleanup;
+ p += bvec->bv_len;
}
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index fbc737e2eeb33..132d3af8fba82 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -561,7 +561,7 @@ cifs_init_inodecache(void)
{
cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
sizeof (struct cifsInodeInfo),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
cifs_init_once, NULL);
if (cifs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 9d39ef496b627..11b7eb1e7a46c 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -69,7 +69,7 @@ int coda_init_inodecache(void)
{
coda_inode_cachep = kmem_cache_create("coda_inode_cache",
sizeof(struct coda_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (coda_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/compat.c b/fs/compat.c
index 07f06a3076d7f..7f471d7aa9c70 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -429,6 +429,8 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
fn = d_path(filp->f_dentry,
filp->f_vfsmnt, path,
PAGE_SIZE);
+ if (IS_ERR(fn))
+ fn = "?";
}
sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
@@ -1373,14 +1375,14 @@ int compat_do_execve(char * filename,
int retval;
int i;
- sched_balance_exec();
-
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
return retval;
+ sched_exec();
+
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
@@ -1390,6 +1392,8 @@ int compat_do_execve(char * filename,
bprm.sh_bang = 0;
bprm.loader = 0;
bprm.exec = 0;
+ bprm.interp_flags = 0;
+ bprm.interp_data = 0;
bprm.security = NULL;
bprm.mm = mm_alloc();
retval = -ENOMEM;
diff --git a/fs/efs/super.c b/fs/efs/super.c
index d4910e43a154a..01444a0b05695 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -58,7 +58,7 @@ static int init_inodecache(void)
{
efs_inode_cachep = kmem_cache_create("efs_inode_cache",
sizeof(struct efs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (efs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/exec.c b/fs/exec.c
index 92b788cd4394b..8445c8e2239d8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -546,6 +546,7 @@ static int exec_mmap(struct mm_struct *mm)
tsk->active_mm = mm;
activate_mm(active_mm, mm);
task_unlock(tsk);
+ arch_pick_mmap_layout(mm);
if (old_mm) {
if (active_mm != old_mm) BUG();
mmput(old_mm);
@@ -1102,7 +1103,7 @@ int do_execve(char * filename,
if (IS_ERR(file))
return retval;
- sched_balance_exec();
+ sched_exec();
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
@@ -1210,7 +1211,7 @@ EXPORT_SYMBOL(set_binfmt);
* name into corename, which must have space for at least
* CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
*/
-void format_corename(char *corename, const char *pattern, long signr)
+static void format_corename(char *corename, const char *pattern, long signr)
{
const char *pat_ptr = pattern;
char *out_ptr = corename;
@@ -1374,7 +1375,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
struct file * file;
int retval = 0;
- lock_kernel();
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
goto fail;
@@ -1392,7 +1392,13 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
goto fail_unlock;
- format_corename(corename, core_pattern, signr);
+ /*
+ * lock_kernel() because format_corename() is controlled by sysctl, which
+ * uses lock_kernel()
+ */
+ lock_kernel();
+ format_corename(corename, core_pattern, signr);
+ unlock_kernel();
file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600);
if (IS_ERR(file))
goto fail_unlock;
@@ -1419,6 +1425,5 @@ close_fail:
fail_unlock:
complete_all(&mm->core_done);
fail:
- unlock_kernel();
return retval;
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index aeef14cd3fd4f..28a820e3f27ae 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -190,7 +190,7 @@ static int init_inodecache(void)
{
ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
sizeof(struct ext2_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (ext2_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index ee7dcaa1f1954..1274b1f790b01 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -477,7 +477,7 @@ static int init_inodecache(void)
{
ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
sizeof(struct ext3_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (ext3_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index ba1707a5ce3e9..3b48219aefbef 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -90,12 +90,6 @@ void fat_truncate(struct inode *inode)
const unsigned int cluster_size = sbi->cluster_size;
int nr_clusters;
- /* Why no return value? Surely the disk could fail... */
- if (IS_RDONLY (inode))
- return /* -EPERM */;
- if (IS_IMMUTABLE(inode))
- return /* -EPERM */;
-
/*
* This protects against truncating a file bigger than it was then
* trying to write into the hole.
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index c0fc6b7d6a987..a85a9eea09a68 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -744,7 +744,7 @@ int __init fat_init_inodecache(void)
{
fat_inode_cachep = kmem_cache_create("fat_inode_cache",
sizeof(struct msdos_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (fat_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
new file mode 100644
index 0000000000000..0f8e01cb3c3ff
--- /dev/null
+++ b/fs/hostfs/Makefile
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
+# to __st_ino. It stayed in the same place, so as long as the correct name
+# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
+
+STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
+ echo __)st_ino
+
+hostfs-objs := hostfs_kern.o hostfs_user.o
+
+obj-y =
+obj-$(CONFIG_HOSTFS) += hostfs.o
+
+SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+
+USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
+USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+
+USER_CFLAGS += -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
+
+$(USER_OBJS) : %.o: %.c
+ $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
new file mode 100644
index 0000000000000..da7849df52b32
--- /dev/null
+++ b/fs/hostfs/hostfs.h
@@ -0,0 +1,79 @@
+#ifndef __UM_FS_HOSTFS
+#define __UM_FS_HOSTFS
+
+#include "os.h"
+
+/* These are exactly the same definitions as in fs.h, but the names are
+ * changed so that this file can be included in both kernel and user files.
+ */
+
+#define HOSTFS_ATTR_MODE 1
+#define HOSTFS_ATTR_UID 2
+#define HOSTFS_ATTR_GID 4
+#define HOSTFS_ATTR_SIZE 8
+#define HOSTFS_ATTR_ATIME 16
+#define HOSTFS_ATTR_MTIME 32
+#define HOSTFS_ATTR_CTIME 64
+#define HOSTFS_ATTR_ATIME_SET 128
+#define HOSTFS_ATTR_MTIME_SET 256
+#define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */
+#define HOSTFS_ATTR_ATTR_FLAG 1024
+
+struct hostfs_iattr {
+ unsigned int ia_valid;
+ mode_t ia_mode;
+ uid_t ia_uid;
+ gid_t ia_gid;
+ loff_t ia_size;
+ struct timespec ia_atime;
+ struct timespec ia_mtime;
+ struct timespec ia_ctime;
+ unsigned int ia_attr_flags;
+};
+
+extern int stat_file(const char *path, unsigned long long *inode_out,
+ int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
+ unsigned long long *size_out, struct timespec *atime_out,
+ struct timespec *mtime_out, struct timespec *ctime_out,
+ int *blksize_out, unsigned long long *blocks_out);
+extern int access_file(char *path, int r, int w, int x);
+extern int open_file(char *path, int r, int w, int append);
+extern int file_type(const char *path, int *rdev);
+extern void *open_dir(char *path, int *err_out);
+extern char *read_dir(void *stream, unsigned long long *pos,
+ unsigned long long *ino_out, int *len_out);
+extern void close_file(void *stream);
+extern void close_dir(void *stream);
+extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
+extern int write_file(int fd, unsigned long long *offset, const char *buf,
+ int len);
+extern int lseek_file(int fd, long long offset, int whence);
+extern int file_create(char *name, int ur, int uw, int ux, int gr,
+ int gw, int gx, int or, int ow, int ox);
+extern int set_attr(const char *file, struct hostfs_iattr *attrs);
+extern int make_symlink(const char *from, const char *to);
+extern int unlink_file(const char *file);
+extern int do_mkdir(const char *file, int mode);
+extern int do_rmdir(const char *file);
+extern int do_mknod(const char *file, int mode, int dev);
+extern int link_file(const char *from, const char *to);
+extern int do_readlink(char *file, char *buf, int size);
+extern int rename_file(char *from, char *to);
+extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
+ long long *bfree_out, long long *bavail_out,
+ long long *files_out, long long *ffree_out,
+ void *fsid_out, int fsid_size, long *namelen_out,
+ long *spare_out);
+
+#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/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
new file mode 100644
index 0000000000000..74fa6642cf5dd
--- /dev/null
+++ b/fs/hostfs/hostfs_kern.c
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ *
+ * Ported the filesystem routines to 2.5.
+ * 2003-02-10 Petr Baudis <pasky@ucw.cz>
+ */
+
+#include <linux/stddef.h>
+#include <linux/fs.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/buffer_head.h>
+#include <linux/root_dev.h>
+#include <linux/statfs.h>
+#include <asm/uaccess.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "user_util.h"
+#include "2_5compat.h"
+#include "init.h"
+
+struct hostfs_inode_info {
+ char *host_filename;
+ int fd;
+ int mode;
+ struct inode vfs_inode;
+};
+
+static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
+{
+ return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
+}
+
+#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode)
+
+int hostfs_d_delete(struct dentry *dentry)
+{
+ return(1);
+}
+
+struct dentry_operations hostfs_dentry_ops = {
+ .d_delete = hostfs_d_delete,
+};
+
+/* Changed in hostfs_args before the kernel starts running */
+static char *root_ino = "/";
+static int append = 0;
+
+#define HOSTFS_SUPER_MAGIC 0x00c0ffee
+
+static struct inode_operations hostfs_iops;
+static struct inode_operations hostfs_dir_iops;
+static struct address_space_operations hostfs_link_aops;
+
+#ifndef MODULE
+static int __init hostfs_args(char *options, int *add)
+{
+ char *ptr;
+
+ ptr = strchr(options, ',');
+ if(ptr != NULL)
+ *ptr++ = '\0';
+ if(*options != '\0')
+ root_ino = options;
+
+ options = ptr;
+ while(options){
+ ptr = strchr(options, ',');
+ if(ptr != NULL)
+ *ptr++ = '\0';
+ if(*options != '\0'){
+ if(!strcmp(options, "append"))
+ append = 1;
+ else printf("hostfs_args - unsupported option - %s\n",
+ options);
+ }
+ options = ptr;
+ }
+ return(0);
+}
+
+__uml_setup("hostfs=", hostfs_args,
+"hostfs=<root dir>,<flags>,...\n"
+" This is used to set hostfs parameters. The root directory argument\n"
+" is used to confine all hostfs mounts to within the specified directory\n"
+" tree on the host. If this isn't specified, then a user inside UML can\n"
+" mount anything on the host that's accessible to the user that's running\n"
+" it.\n"
+" The only flag currently supported is 'append', which specifies that all\n"
+" files opened by hostfs will be opened in append mode.\n\n"
+);
+#endif
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+ struct dentry *parent;
+ char *root, *name;
+ int len;
+
+ len = 0;
+ parent = dentry;
+ while(parent->d_parent != parent){
+ len += parent->d_name.len + 1;
+ parent = parent->d_parent;
+ }
+
+ root = HOSTFS_I(parent->d_inode)->host_filename;
+ len += strlen(root);
+ name = kmalloc(len + extra + 1, GFP_KERNEL);
+ if(name == NULL) return(NULL);
+
+ name[len] = '\0';
+ parent = dentry;
+ while(parent->d_parent != parent){
+ len -= parent->d_name.len + 1;
+ name[len] = '/';
+ strncpy(&name[len + 1], parent->d_name.name,
+ parent->d_name.len);
+ parent = parent->d_parent;
+ }
+ strncpy(name, root, strlen(root));
+ return(name);
+}
+
+static char *inode_name(struct inode *ino, int extra)
+{
+ struct dentry *dentry;
+
+ dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
+ return(dentry_name(dentry, extra));
+}
+
+static int read_name(struct inode *ino, char *name)
+{
+ /* The non-int inode fields are copied into ints by stat_file and
+ * then copied into the inode because passing the actual pointers
+ * in and having them treated as int * breaks on big-endian machines
+ */
+ int err;
+ int i_mode, i_nlink, i_blksize;
+ unsigned long long i_size;
+ unsigned long long i_ino;
+ unsigned long long i_blocks;
+
+ err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
+ &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
+ &ino->i_ctime, &i_blksize, &i_blocks);
+ if(err)
+ return(err);
+
+ ino->i_ino = i_ino;
+ ino->i_mode = i_mode;
+ ino->i_nlink = i_nlink;
+ ino->i_size = i_size;
+ ino->i_blksize = i_blksize;
+ ino->i_blocks = i_blocks;
+ if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid()))
+ ino->i_uid = 0;
+ return(0);
+}
+
+static char *follow_link(char *link)
+{
+ int len, n;
+ char *name, *resolved, *end;
+
+ len = 64;
+ while(1){
+ n = -ENOMEM;
+ name = kmalloc(len, GFP_KERNEL);
+ if(name == NULL)
+ goto out;
+
+ n = do_readlink(link, name, len);
+ if(n < len)
+ break;
+ len *= 2;
+ kfree(name);
+ }
+ if(n < 0)
+ goto out_free;
+
+ if(*name == '/')
+ return(name);
+
+ end = strrchr(link, '/');
+ if(end == NULL)
+ return(name);
+
+ *(end + 1) = '\0';
+ len = strlen(link) + strlen(name) + 1;
+
+ resolved = kmalloc(len, GFP_KERNEL);
+ if(resolved == NULL){
+ n = -ENOMEM;
+ goto out_free;
+ }
+
+ sprintf(resolved, "%s%s", link, name);
+ kfree(name);
+ kfree(link);
+ return(resolved);
+
+ out_free:
+ kfree(name);
+ out:
+ return(ERR_PTR(n));
+}
+
+static int read_inode(struct inode *ino)
+{
+ char *name;
+ int err = 0;
+
+ /* Unfortunately, we are called from iget() when we don't have a dentry
+ * allocated yet.
+ */
+ if(list_empty(&ino->i_dentry))
+ goto out;
+
+ err = -ENOMEM;
+ name = inode_name(ino, 0);
+ if(name == NULL)
+ goto out;
+
+ if(file_type(name, NULL) == OS_TYPE_SYMLINK){
+ name = follow_link(name);
+ if(IS_ERR(name)){
+ err = PTR_ERR(name);
+ goto out;
+ }
+ }
+
+ err = read_name(ino, name);
+ kfree(name);
+ out:
+ return(err);
+}
+
+int hostfs_statfs(struct super_block *sb, struct kstatfs *sf)
+{
+ /* do_statfs uses struct statfs64 internally, but the linux kernel
+ * struct statfs still has 32-bit versions for most of these fields,
+ * so we convert them here
+ */
+ int err;
+ long long f_blocks;
+ long long f_bfree;
+ long long f_bavail;
+ long long f_files;
+ long long f_ffree;
+
+ err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename,
+ &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
+ &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
+ &sf->f_namelen, sf->f_spare);
+ if(err) return(err);
+ sf->f_blocks = f_blocks;
+ sf->f_bfree = f_bfree;
+ sf->f_bavail = f_bavail;
+ sf->f_files = f_files;
+ sf->f_ffree = f_ffree;
+ sf->f_type = HOSTFS_SUPER_MAGIC;
+ return(0);
+}
+
+static struct inode *hostfs_alloc_inode(struct super_block *sb)
+{
+ struct hostfs_inode_info *hi;
+
+ hi = kmalloc(sizeof(*hi), GFP_KERNEL);
+ if(hi == NULL)
+ return(NULL);
+
+ *hi = ((struct hostfs_inode_info) { .host_filename = NULL,
+ .fd = -1,
+ .mode = 0 });
+ inode_init_once(&hi->vfs_inode);
+ return(&hi->vfs_inode);
+}
+
+static void hostfs_delete_inode(struct inode *inode)
+{
+ if(HOSTFS_I(inode)->fd != -1) {
+ close_file(&HOSTFS_I(inode)->fd);
+ printk("Closing host fd in .delete_inode\n");
+ HOSTFS_I(inode)->fd = -1;
+ }
+ clear_inode(inode);
+}
+
+static void hostfs_destroy_inode(struct inode *inode)
+{
+ if(HOSTFS_I(inode)->host_filename)
+ kfree(HOSTFS_I(inode)->host_filename);
+
+ if(HOSTFS_I(inode)->fd != -1) {
+ close_file(&HOSTFS_I(inode)->fd);
+ printk("Closing host fd in .destroy_inode\n");
+ }
+
+ kfree(HOSTFS_I(inode));
+}
+
+static void hostfs_read_inode(struct inode *inode)
+{
+ read_inode(inode);
+}
+
+static struct super_operations hostfs_sbops = {
+ .alloc_inode = hostfs_alloc_inode,
+ .drop_inode = generic_delete_inode,
+ .delete_inode = hostfs_delete_inode,
+ .destroy_inode = hostfs_destroy_inode,
+ .read_inode = hostfs_read_inode,
+ .statfs = hostfs_statfs,
+};
+
+int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+ void *dir;
+ char *name;
+ unsigned long long next, ino;
+ int error, len;
+
+ name = dentry_name(file->f_dentry, 0);
+ if(name == NULL) return(-ENOMEM);
+ dir = open_dir(name, &error);
+ kfree(name);
+ if(dir == NULL) return(-error);
+ next = file->f_pos;
+ while((name = read_dir(dir, &next, &ino, &len)) != NULL){
+ error = (*filldir)(ent, name, len, file->f_pos,
+ ino, DT_UNKNOWN);
+ if(error) break;
+ file->f_pos = next;
+ }
+ close_dir(dir);
+ return(0);
+}
+
+int hostfs_file_open(struct inode *ino, struct file *file)
+{
+ char *name;
+ int mode = 0, r = 0, w = 0, fd;
+
+ mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
+ if((mode & HOSTFS_I(ino)->mode) == mode)
+ return(0);
+
+ /* The file may already have been opened, but with the wrong access,
+ * so this resets things and reopens the file with the new access.
+ */
+ if(HOSTFS_I(ino)->fd != -1){
+ close_file(&HOSTFS_I(ino)->fd);
+ HOSTFS_I(ino)->fd = -1;
+ }
+
+ HOSTFS_I(ino)->mode |= mode;
+ if(HOSTFS_I(ino)->mode & FMODE_READ)
+ r = 1;
+ if(HOSTFS_I(ino)->mode & FMODE_WRITE)
+ w = 1;
+ if(w)
+ r = 1;
+
+ name = dentry_name(file->f_dentry, 0);
+ if(name == NULL)
+ return(-ENOMEM);
+
+ fd = open_file(name, r, w, append);
+ kfree(name);
+ if(fd < 0) return(fd);
+ FILE_HOSTFS_I(file)->fd = fd;
+
+ return(0);
+}
+
+int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ return(0);
+}
+
+static struct file_operations hostfs_file_fops = {
+ .llseek = generic_file_llseek,
+ .read = generic_file_read,
+ .write = generic_file_write,
+ .mmap = generic_file_mmap,
+ .open = hostfs_file_open,
+ .release = NULL,
+ .fsync = hostfs_fsync,
+};
+
+static struct file_operations hostfs_dir_fops = {
+ .readdir = hostfs_readdir,
+ .read = generic_read_dir,
+};
+
+int hostfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode = mapping->host;
+ char *buffer;
+ unsigned long long base;
+ int count = PAGE_CACHE_SIZE;
+ int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ int err;
+
+ if (page->index >= end_index)
+ count = inode->i_size & (PAGE_CACHE_SIZE-1);
+
+ buffer = kmap(page);
+ base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
+
+ err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
+ if(err != count){
+ ClearPageUptodate(page);
+ goto out;
+ }
+
+ if (base > inode->i_size)
+ inode->i_size = base;
+
+ if (PageError(page))
+ ClearPageError(page);
+ err = 0;
+
+ out:
+ kunmap(page);
+
+ unlock_page(page);
+ return err;
+}
+
+int hostfs_readpage(struct file *file, struct page *page)
+{
+ char *buffer;
+ long long start;
+ int err = 0;
+
+ start = (long long) page->index << PAGE_CACHE_SHIFT;
+ buffer = kmap(page);
+ err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
+ PAGE_CACHE_SIZE);
+ if(err < 0) goto out;
+
+ memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
+
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ if (PageError(page)) ClearPageError(page);
+ err = 0;
+ out:
+ kunmap(page);
+ unlock_page(page);
+ return(err);
+}
+
+int hostfs_prepare_write(struct file *file, struct page *page,
+ unsigned int from, unsigned int to)
+{
+ char *buffer;
+ long long start, tmp;
+ int err;
+
+ start = (long long) page->index << PAGE_CACHE_SHIFT;
+ buffer = kmap(page);
+ if(from != 0){
+ tmp = start;
+ err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer,
+ from);
+ if(err < 0) goto out;
+ }
+ if(to != PAGE_CACHE_SIZE){
+ start += to;
+ err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to,
+ PAGE_CACHE_SIZE - to);
+ if(err < 0) goto out;
+ }
+ err = 0;
+ out:
+ kunmap(page);
+ return(err);
+}
+
+int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
+ unsigned to)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode = mapping->host;
+ char *buffer;
+ long long start;
+ int err = 0;
+
+ start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
+ buffer = kmap(page);
+ err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from,
+ to - from);
+ if(err > 0) err = 0;
+ if(!err && (start > inode->i_size))
+ inode->i_size = start;
+
+ kunmap(page);
+ return(err);
+}
+
+static struct address_space_operations hostfs_aops = {
+ .writepage = hostfs_writepage,
+ .readpage = hostfs_readpage,
+/* .set_page_dirty = __set_page_dirty_nobuffers, */
+ .prepare_write = hostfs_prepare_write,
+ .commit_write = hostfs_commit_write
+};
+
+static int init_inode(struct inode *inode, struct dentry *dentry)
+{
+ char *name;
+ int type, err = -ENOMEM, rdev;
+
+ if(dentry){
+ name = dentry_name(dentry, 0);
+ if(name == NULL)
+ goto out;
+ type = file_type(name, &rdev);
+ kfree(name);
+ }
+ else type = OS_TYPE_DIR;
+
+ err = 0;
+ if(type == OS_TYPE_SYMLINK)
+ inode->i_op = &page_symlink_inode_operations;
+ else if(type == OS_TYPE_DIR)
+ inode->i_op = &hostfs_dir_iops;
+ else inode->i_op = &hostfs_iops;
+
+ if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
+ else inode->i_fop = &hostfs_file_fops;
+
+ if(type == OS_TYPE_SYMLINK)
+ inode->i_mapping->a_ops = &hostfs_link_aops;
+ else inode->i_mapping->a_ops = &hostfs_aops;
+
+ switch (type) {
+ case OS_TYPE_CHARDEV:
+ init_special_inode(inode, S_IFCHR, rdev);
+ break;
+ case OS_TYPE_BLOCKDEV:
+ init_special_inode(inode, S_IFBLK, rdev);
+ break;
+ case OS_TYPE_FIFO:
+ init_special_inode(inode, S_IFIFO, 0);
+ break;
+ case OS_TYPE_SOCK:
+ init_special_inode(inode, S_IFSOCK, 0);
+ break;
+ }
+ out:
+ return(err);
+}
+
+int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ struct inode *inode;
+ char *name;
+ int error, fd;
+
+ error = -ENOMEM;
+ inode = iget(dir->i_sb, 0);
+ if(inode == NULL) goto out;
+
+ error = init_inode(inode, dentry);
+ if(error)
+ goto out_put;
+
+ error = -ENOMEM;
+ name = dentry_name(dentry, 0);
+ if(name == NULL)
+ goto out_put;
+
+ fd = file_create(name,
+ mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR,
+ mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP,
+ mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
+ if(fd < 0)
+ error = fd;
+ else error = read_name(inode, name);
+
+ kfree(name);
+ if(error)
+ goto out_put;
+
+ HOSTFS_I(inode)->fd = fd;
+ HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
+ d_instantiate(dentry, inode);
+ return(0);
+
+ out_put:
+ iput(inode);
+ out:
+ return(error);
+}
+
+struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct inode *inode;
+ char *name;
+ int err;
+
+ err = -ENOMEM;
+ inode = iget(ino->i_sb, 0);
+ if(inode == NULL)
+ goto out;
+
+ err = init_inode(inode, dentry);
+ if(err)
+ goto out_put;
+
+ err = -ENOMEM;
+ name = dentry_name(dentry, 0);
+ if(name == NULL)
+ goto out_put;
+
+ err = read_name(inode, name);
+ kfree(name);
+ if(err == -ENOENT){
+ iput(inode);
+ inode = NULL;
+ }
+ else if(err)
+ goto out_put;
+
+ d_add(dentry, inode);
+ dentry->d_op = &hostfs_dentry_ops;
+ return(NULL);
+
+ out_put:
+ iput(inode);
+ out:
+ return(ERR_PTR(err));
+}
+
+static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
+{
+ char *file;
+ int len;
+
+ file = inode_name(ino, dentry->d_name.len + 1);
+ if(file == NULL) return(NULL);
+ strcat(file, "/");
+ len = strlen(file);
+ strncat(file, dentry->d_name.name, dentry->d_name.len);
+ file[len + dentry->d_name.len] = '\0';
+ return(file);
+}
+
+int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
+{
+ char *from_name, *to_name;
+ int err;
+
+ if((from_name = inode_dentry_name(ino, from)) == NULL)
+ return(-ENOMEM);
+ to_name = dentry_name(to, 0);
+ if(to_name == NULL){
+ kfree(from_name);
+ return(-ENOMEM);
+ }
+ err = link_file(to_name, from_name);
+ kfree(from_name);
+ kfree(to_name);
+ return(err);
+}
+
+int hostfs_unlink(struct inode *ino, struct dentry *dentry)
+{
+ char *file;
+ int err;
+
+ if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ if(append)
+ return(-EPERM);
+
+ err = unlink_file(file);
+ kfree(file);
+ return(err);
+}
+
+int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
+{
+ char *file;
+ int err;
+
+ if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ err = make_symlink(file, to);
+ kfree(file);
+ return(err);
+}
+
+int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
+{
+ char *file;
+ int err;
+
+ if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ err = do_mkdir(file, mode);
+ kfree(file);
+ return(err);
+}
+
+int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
+{
+ char *file;
+ int err;
+
+ if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ err = do_rmdir(file);
+ kfree(file);
+ return(err);
+}
+
+int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ struct inode *inode;
+ char *name;
+ int err = -ENOMEM;
+
+ inode = iget(dir->i_sb, 0);
+ if(inode == NULL)
+ goto out;
+
+ err = init_inode(inode, dentry);
+ if(err)
+ goto out_put;
+
+ err = -ENOMEM;
+ name = dentry_name(dentry, 0);
+ if(name == NULL)
+ goto out_put;
+
+ init_special_inode(inode, mode, dev);
+ err = do_mknod(name, mode, dev);
+ if(err)
+ goto out_free;
+
+ err = read_name(inode, name);
+ kfree(name);
+ if(err)
+ goto out_put;
+
+ d_instantiate(dentry, inode);
+ return(0);
+
+ out_free:
+ kfree(name);
+ out_put:
+ iput(inode);
+ out:
+ return(err);
+}
+
+int hostfs_rename(struct inode *from_ino, struct dentry *from,
+ struct inode *to_ino, struct dentry *to)
+{
+ char *from_name, *to_name;
+ int err;
+
+ if((from_name = inode_dentry_name(from_ino, from)) == NULL)
+ return(-ENOMEM);
+ if((to_name = inode_dentry_name(to_ino, to)) == NULL){
+ kfree(from_name);
+ return(-ENOMEM);
+ }
+ err = rename_file(from_name, to_name);
+ kfree(from_name);
+ kfree(to_name);
+ return(err);
+}
+
+void hostfs_truncate(struct inode *ino)
+{
+ not_implemented();
+}
+
+int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
+{
+ char *name;
+ int r = 0, w = 0, x = 0, err;
+
+ if(desired & MAY_READ) r = 1;
+ if(desired & MAY_WRITE) w = 1;
+ if(desired & MAY_EXEC) x = 1;
+ name = inode_name(ino, 0);
+ if(name == NULL) return(-ENOMEM);
+ err = access_file(name, r, w, x);
+ kfree(name);
+ if(!err) err = vfs_permission(ino, desired);
+ return(err);
+}
+
+int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct hostfs_iattr attrs;
+ char *name;
+ int err;
+
+ if(append)
+ attr->ia_valid &= ~ATTR_SIZE;
+
+ attrs.ia_valid = 0;
+ if(attr->ia_valid & ATTR_MODE){
+ attrs.ia_valid |= HOSTFS_ATTR_MODE;
+ attrs.ia_mode = attr->ia_mode;
+ }
+ if(attr->ia_valid & ATTR_UID){
+ if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) &&
+ (attr->ia_uid == 0))
+ attr->ia_uid = getuid();
+ attrs.ia_valid |= HOSTFS_ATTR_UID;
+ attrs.ia_uid = attr->ia_uid;
+ }
+ if(attr->ia_valid & ATTR_GID){
+ if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) &&
+ (attr->ia_gid == 0))
+ attr->ia_gid = getuid();
+ attrs.ia_valid |= HOSTFS_ATTR_GID;
+ attrs.ia_gid = attr->ia_gid;
+ }
+ if(attr->ia_valid & ATTR_SIZE){
+ attrs.ia_valid |= HOSTFS_ATTR_SIZE;
+ attrs.ia_size = attr->ia_size;
+ }
+ if(attr->ia_valid & ATTR_ATIME){
+ attrs.ia_valid |= HOSTFS_ATTR_ATIME;
+ attrs.ia_atime = attr->ia_atime;
+ }
+ if(attr->ia_valid & ATTR_MTIME){
+ attrs.ia_valid |= HOSTFS_ATTR_MTIME;
+ attrs.ia_mtime = attr->ia_mtime;
+ }
+ if(attr->ia_valid & ATTR_CTIME){
+ attrs.ia_valid |= HOSTFS_ATTR_CTIME;
+ attrs.ia_ctime = attr->ia_ctime;
+ }
+ if(attr->ia_valid & ATTR_ATIME_SET){
+ attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
+ }
+ if(attr->ia_valid & ATTR_MTIME_SET){
+ attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
+ }
+ name = dentry_name(dentry, 0);
+ if(name == NULL) return(-ENOMEM);
+ err = set_attr(name, &attrs);
+ kfree(name);
+ if(err)
+ return(err);
+
+ return(inode_setattr(dentry->d_inode, attr));
+}
+
+int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ generic_fillattr(dentry->d_inode, stat);
+ return(0);
+}
+
+static struct inode_operations hostfs_iops = {
+ .create = hostfs_create,
+ .link = hostfs_link,
+ .unlink = hostfs_unlink,
+ .symlink = hostfs_symlink,
+ .mkdir = hostfs_mkdir,
+ .rmdir = hostfs_rmdir,
+ .mknod = hostfs_mknod,
+ .rename = hostfs_rename,
+ .truncate = hostfs_truncate,
+ .permission = hostfs_permission,
+ .setattr = hostfs_setattr,
+ .getattr = hostfs_getattr,
+};
+
+static struct inode_operations hostfs_dir_iops = {
+ .create = hostfs_create,
+ .lookup = hostfs_lookup,
+ .link = hostfs_link,
+ .unlink = hostfs_unlink,
+ .symlink = hostfs_symlink,
+ .mkdir = hostfs_mkdir,
+ .rmdir = hostfs_rmdir,
+ .mknod = hostfs_mknod,
+ .rename = hostfs_rename,
+ .truncate = hostfs_truncate,
+ .permission = hostfs_permission,
+ .setattr = hostfs_setattr,
+ .getattr = hostfs_getattr,
+};
+
+int hostfs_link_readpage(struct file *file, struct page *page)
+{
+ char *buffer, *name;
+ long long start;
+ int err;
+
+ start = page->index << PAGE_CACHE_SHIFT;
+ buffer = kmap(page);
+ name = inode_name(page->mapping->host, 0);
+ if(name == NULL) return(-ENOMEM);
+ err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
+ kfree(name);
+ if(err == PAGE_CACHE_SIZE)
+ err = -E2BIG;
+ else if(err > 0){
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ if (PageError(page)) ClearPageError(page);
+ err = 0;
+ }
+ kunmap(page);
+ unlock_page(page);
+ return(err);
+}
+
+static struct address_space_operations hostfs_link_aops = {
+ .readpage = hostfs_link_readpage,
+};
+
+static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
+{
+ struct inode *root_inode;
+ char *name, *data = d;
+ int err;
+
+ sb->s_blocksize = 1024;
+ sb->s_blocksize_bits = 10;
+ sb->s_magic = HOSTFS_SUPER_MAGIC;
+ sb->s_op = &hostfs_sbops;
+
+ if((data == NULL) || (*data == '\0'))
+ data = root_ino;
+
+ err = -ENOMEM;
+ name = kmalloc(strlen(data) + 1, GFP_KERNEL);
+ if(name == NULL)
+ goto out;
+
+ strcpy(name, data);
+
+ root_inode = iget(sb, 0);
+ if(root_inode == NULL)
+ goto out_free;
+
+ err = init_inode(root_inode, NULL);
+ if(err)
+ goto out_put;
+
+ HOSTFS_I(root_inode)->host_filename = name;
+
+ err = -ENOMEM;
+ sb->s_root = d_alloc_root(root_inode);
+ if(sb->s_root == NULL)
+ goto out_put;
+
+ err = read_inode(root_inode);
+ if(err)
+ goto out_put;
+
+ return(0);
+
+ out_put:
+ iput(root_inode);
+ out_free:
+ kfree(name);
+ out:
+ return(err);
+}
+
+static struct super_block *hostfs_read_sb(struct file_system_type *type,
+ int flags, const char *dev_name,
+ void *data)
+{
+ return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common));
+}
+
+static struct file_system_type hostfs_type = {
+ .owner = THIS_MODULE,
+ .name = "hostfs",
+ .get_sb = hostfs_read_sb,
+ .kill_sb = kill_anon_super,
+ .fs_flags = 0,
+};
+
+static int __init init_hostfs(void)
+{
+ return(register_filesystem(&hostfs_type));
+}
+
+static void __exit exit_hostfs(void)
+{
+ unregister_filesystem(&hostfs_type);
+}
+
+module_init(init_hostfs)
+module_exit(exit_hostfs)
+MODULE_LICENSE("GPL");
+
+/*
+ * 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/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
new file mode 100644
index 0000000000000..31ae92babf318
--- /dev/null
+++ b/fs/hostfs/hostfs_user.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <utime.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vfs.h>
+#include "hostfs.h"
+#include "kern_util.h"
+#include "user.h"
+
+int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
+ int *nlink_out, int *uid_out, int *gid_out,
+ unsigned long long *size_out, struct timespec *atime_out,
+ struct timespec *mtime_out, struct timespec *ctime_out,
+ int *blksize_out, unsigned long long *blocks_out)
+{
+ struct stat64 buf;
+
+ if(lstat64(path, &buf) < 0)
+ return(-errno);
+
+ /* See the Makefile for why STAT64_INO_FIELD is passed in
+ * by the build
+ */
+ if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD;
+ if(mode_out != NULL) *mode_out = buf.st_mode;
+ if(nlink_out != NULL) *nlink_out = buf.st_nlink;
+ if(uid_out != NULL) *uid_out = buf.st_uid;
+ if(gid_out != NULL) *gid_out = buf.st_gid;
+ if(size_out != NULL) *size_out = buf.st_size;
+ if(atime_out != NULL) {
+ atime_out->tv_sec = buf.st_atime;
+ atime_out->tv_nsec = 0;
+ }
+ if(mtime_out != NULL) {
+ mtime_out->tv_sec = buf.st_mtime;
+ mtime_out->tv_nsec = 0;
+ }
+ if(ctime_out != NULL) {
+ ctime_out->tv_sec = buf.st_ctime;
+ ctime_out->tv_nsec = 0;
+ }
+ if(blksize_out != NULL) *blksize_out = buf.st_blksize;
+ if(blocks_out != NULL) *blocks_out = buf.st_blocks;
+ return(0);
+}
+
+int file_type(const char *path, int *rdev)
+{
+ struct stat64 buf;
+
+ if(lstat64(path, &buf) < 0)
+ return(-errno);
+ if(rdev != NULL)
+ *rdev = buf.st_rdev;
+
+ if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
+ else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
+ else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
+ else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
+ else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
+ else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
+ else return(OS_TYPE_FILE);
+}
+
+int access_file(char *path, int r, int w, int x)
+{
+ int mode = 0;
+
+ if(r) mode = R_OK;
+ if(w) mode |= W_OK;
+ if(x) mode |= X_OK;
+ if(access(path, mode) != 0) return(-errno);
+ else return(0);
+}
+
+int open_file(char *path, int r, int w, int append)
+{
+ int mode = 0, fd;
+
+ if(r && !w)
+ mode = O_RDONLY;
+ else if(!r && w)
+ mode = O_WRONLY;
+ else if(r && w)
+ mode = O_RDWR;
+ else panic("Impossible mode in open_file");
+
+ if(append)
+ mode |= O_APPEND;
+ fd = open64(path, mode);
+ if(fd < 0) return(-errno);
+ else return(fd);
+}
+
+void *open_dir(char *path, int *err_out)
+{
+ DIR *dir;
+
+ dir = opendir(path);
+ *err_out = errno;
+ if(dir == NULL) return(NULL);
+ return(dir);
+}
+
+char *read_dir(void *stream, unsigned long long *pos,
+ unsigned long long *ino_out, int *len_out)
+{
+ DIR *dir = stream;
+ struct dirent *ent;
+
+ seekdir(dir, *pos);
+ ent = readdir(dir);
+ if(ent == NULL) return(NULL);
+ *len_out = strlen(ent->d_name);
+ *ino_out = ent->d_ino;
+ *pos = telldir(dir);
+ return(ent->d_name);
+}
+
+int read_file(int fd, unsigned long long *offset, char *buf, int len)
+{
+ int n;
+
+ n = pread64(fd, buf, len, *offset);
+ if(n < 0) return(-errno);
+ *offset += n;
+ return(n);
+}
+
+int write_file(int fd, unsigned long long *offset, const char *buf, int len)
+{
+ int n;
+
+ n = pwrite64(fd, buf, len, *offset);
+ if(n < 0) return(-errno);
+ *offset += n;
+ return(n);
+}
+
+int lseek_file(int fd, long long offset, int whence)
+{
+ int ret;
+
+ ret = lseek64(fd, offset, whence);
+ if(ret < 0) return(-errno);
+ return(0);
+}
+
+void close_file(void *stream)
+{
+ close(*((int *) stream));
+}
+
+void close_dir(void *stream)
+{
+ closedir(stream);
+}
+
+int file_create(char *name, int ur, int uw, int ux, int gr,
+ int gw, int gx, int or, int ow, int ox)
+{
+ int mode, fd;
+
+ mode = 0;
+ mode |= ur ? S_IRUSR : 0;
+ mode |= uw ? S_IWUSR : 0;
+ mode |= ux ? S_IXUSR : 0;
+ mode |= gr ? S_IRGRP : 0;
+ mode |= gw ? S_IWGRP : 0;
+ mode |= gx ? S_IXGRP : 0;
+ mode |= or ? S_IROTH : 0;
+ mode |= ow ? S_IWOTH : 0;
+ mode |= ox ? S_IXOTH : 0;
+ fd = open64(name, O_CREAT | O_RDWR, mode);
+ if(fd < 0)
+ return(-errno);
+ return(fd);
+}
+
+int set_attr(const char *file, struct hostfs_iattr *attrs)
+{
+ struct utimbuf buf;
+ int err, ma;
+
+ if(attrs->ia_valid & HOSTFS_ATTR_MODE){
+ if(chmod(file, attrs->ia_mode) != 0) return(-errno);
+ }
+ if(attrs->ia_valid & HOSTFS_ATTR_UID){
+ if(chown(file, attrs->ia_uid, -1)) return(-errno);
+ }
+ if(attrs->ia_valid & HOSTFS_ATTR_GID){
+ if(chown(file, -1, attrs->ia_gid)) return(-errno);
+ }
+ if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
+ if(truncate(file, attrs->ia_size)) return(-errno);
+ }
+ ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
+ if((attrs->ia_valid & ma) == ma){
+ buf.actime = attrs->ia_atime.tv_sec;
+ buf.modtime = attrs->ia_mtime.tv_sec;
+ if(utime(file, &buf) != 0) return(-errno);
+ }
+ else {
+ struct timespec ts;
+
+ if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
+ err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &ts, NULL, NULL, NULL);
+ if(err != 0)
+ return(err);
+ buf.actime = attrs->ia_atime.tv_sec;
+ buf.modtime = ts.tv_sec;
+ if(utime(file, &buf) != 0)
+ return(-errno);
+ }
+ if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
+ err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
+ NULL, &ts, NULL, NULL, NULL, NULL);
+ if(err != 0)
+ return(err);
+ buf.actime = ts.tv_sec;
+ buf.modtime = attrs->ia_mtime.tv_sec;
+ if(utime(file, &buf) != 0)
+ return(-errno);
+ }
+ }
+ if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
+ if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
+ err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
+ &attrs->ia_atime, &attrs->ia_mtime, NULL,
+ NULL, NULL);
+ if(err != 0) return(err);
+ }
+ return(0);
+}
+
+int make_symlink(const char *from, const char *to)
+{
+ int err;
+
+ err = symlink(to, from);
+ if(err) return(-errno);
+ return(0);
+}
+
+int unlink_file(const char *file)
+{
+ int err;
+
+ err = unlink(file);
+ if(err) return(-errno);
+ return(0);
+}
+
+int do_mkdir(const char *file, int mode)
+{
+ int err;
+
+ err = mkdir(file, mode);
+ if(err) return(-errno);
+ return(0);
+}
+
+int do_rmdir(const char *file)
+{
+ int err;
+
+ err = rmdir(file);
+ if(err) return(-errno);
+ return(0);
+}
+
+int do_mknod(const char *file, int mode, int dev)
+{
+ int err;
+
+ err = mknod(file, mode, dev);
+ if(err) return(-errno);
+ return(0);
+}
+
+int link_file(const char *to, const char *from)
+{
+ int err;
+
+ err = link(to, from);
+ if(err) return(-errno);
+ return(0);
+}
+
+int do_readlink(char *file, char *buf, int size)
+{
+ int n;
+
+ n = readlink(file, buf, size);
+ if(n < 0)
+ return(-errno);
+ if(n < size)
+ buf[n] = '\0';
+ return(n);
+}
+
+int rename_file(char *from, char *to)
+{
+ int err;
+
+ err = rename(from, to);
+ if(err < 0) return(-errno);
+ return(0);
+}
+
+int do_statfs(char *root, long *bsize_out, long long *blocks_out,
+ long long *bfree_out, long long *bavail_out,
+ long long *files_out, long long *ffree_out,
+ void *fsid_out, int fsid_size, long *namelen_out,
+ long *spare_out)
+{
+ struct statfs64 buf;
+ int err;
+
+ err = statfs64(root, &buf);
+ if(err < 0) return(-errno);
+ *bsize_out = buf.f_bsize;
+ *blocks_out = buf.f_blocks;
+ *bfree_out = buf.f_bfree;
+ *bavail_out = buf.f_bavail;
+ *files_out = buf.f_files;
+ *ffree_out = buf.f_ffree;
+ memcpy(fsid_out, &buf.f_fsid,
+ sizeof(buf.f_fsid) > fsid_size ? fsid_size :
+ sizeof(buf.f_fsid));
+ *namelen_out = buf.f_namelen;
+ spare_out[0] = buf.f_spare[0];
+ spare_out[1] = buf.f_spare[1];
+ spare_out[2] = buf.f_spare[2];
+ spare_out[3] = buf.f_spare[3];
+ spare_out[4] = buf.f_spare[4];
+ spare_out[5] = buf.f_spare[5];
+ 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/fs/hpfs/super.c b/fs/hpfs/super.c
index 714f64447d6ed..34074b3782c3a 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -191,7 +191,7 @@ static int init_inodecache(void)
{
hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
sizeof(struct hpfs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (hpfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/hppfs/Makefile b/fs/hppfs/Makefile
new file mode 100644
index 0000000000000..a2d5c4d05e30d
--- /dev/null
+++ b/fs/hppfs/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+hppfs-objs := hppfs_kern.o
+
+obj-y =
+obj-$(CONFIG_HPPFS) += hppfs.o
+
+clean:
+
+modules:
+
+fastdep:
+
+dep:
+
+archmrproper: clean
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
new file mode 100644
index 0000000000000..f8e0cbd0cb60b
--- /dev/null
+++ b/fs/hppfs/hppfs_kern.c
@@ -0,0 +1,815 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/dcache.h>
+#include <linux/statfs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include "os.h"
+
+static int init_inode(struct inode *inode, struct dentry *dentry);
+
+struct hppfs_data {
+ struct list_head list;
+ char contents[PAGE_SIZE - sizeof(struct list_head)];
+};
+
+struct hppfs_private {
+ struct file *proc_file;
+ int host_fd;
+ loff_t len;
+ struct hppfs_data *contents;
+};
+
+struct hppfs_inode_info {
+ struct dentry *proc_dentry;
+ struct inode vfs_inode;
+};
+
+static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
+{
+ return(list_entry(inode, struct hppfs_inode_info, vfs_inode));
+}
+
+#define HPPFS_SUPER_MAGIC 0xb00000ee
+
+static struct super_operations hppfs_sbops;
+
+static int is_pid(struct dentry *dentry)
+{
+ struct super_block *sb;
+ int i;
+
+ sb = dentry->d_sb;
+ if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
+ return(0);
+
+ for(i = 0; i < dentry->d_name.len; i++){
+ if(!isdigit(dentry->d_name.name[i]))
+ return(0);
+ }
+ return(1);
+}
+
+static char *dentry_name(struct dentry *dentry, int extra)
+{
+ struct dentry *parent;
+ char *root, *name;
+ const char *seg_name;
+ int len, seg_len;
+
+ len = 0;
+ parent = dentry;
+ while(parent->d_parent != parent){
+ if(is_pid(parent))
+ len += strlen("pid") + 1;
+ else len += parent->d_name.len + 1;
+ parent = parent->d_parent;
+ }
+
+ root = "proc";
+ len += strlen(root);
+ name = kmalloc(len + extra + 1, GFP_KERNEL);
+ if(name == NULL) return(NULL);
+
+ name[len] = '\0';
+ parent = dentry;
+ while(parent->d_parent != parent){
+ if(is_pid(parent)){
+ seg_name = "pid";
+ seg_len = strlen("pid");
+ }
+ else {
+ seg_name = parent->d_name.name;
+ seg_len = parent->d_name.len;
+ }
+
+ len -= seg_len + 1;
+ name[len] = '/';
+ strncpy(&name[len + 1], seg_name, seg_len);
+ parent = parent->d_parent;
+ }
+ strncpy(name, root, strlen(root));
+ return(name);
+}
+
+struct dentry_operations hppfs_dentry_ops = {
+};
+
+static int file_removed(struct dentry *dentry, const char *file)
+{
+ char *host_file;
+ int extra, fd;
+
+ extra = 0;
+ if(file != NULL) extra += strlen(file) + 1;
+
+ host_file = dentry_name(dentry, extra + strlen("/remove"));
+ if(host_file == NULL){
+ printk("file_removed : allocation failed\n");
+ return(-ENOMEM);
+ }
+
+ if(file != NULL){
+ strcat(host_file, "/");
+ strcat(host_file, file);
+ }
+ strcat(host_file, "/remove");
+
+ fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
+ kfree(host_file);
+ if(fd > 0){
+ os_close_file(fd);
+ return(1);
+ }
+ return(0);
+}
+
+static void hppfs_read_inode(struct inode *ino)
+{
+ struct inode *proc_ino;
+
+ if(HPPFS_I(ino)->proc_dentry == NULL)
+ return;
+
+ proc_ino = HPPFS_I(ino)->proc_dentry->d_inode;
+ ino->i_uid = proc_ino->i_uid;
+ ino->i_gid = proc_ino->i_gid;
+ ino->i_atime = proc_ino->i_atime;
+ ino->i_mtime = proc_ino->i_mtime;
+ ino->i_ctime = proc_ino->i_ctime;
+ ino->i_ino = proc_ino->i_ino;
+ ino->i_mode = proc_ino->i_mode;
+ ino->i_nlink = proc_ino->i_nlink;
+ ino->i_size = proc_ino->i_size;
+ ino->i_blksize = proc_ino->i_blksize;
+ ino->i_blocks = proc_ino->i_blocks;
+}
+
+static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct dentry *proc_dentry, *new, *parent;
+ struct inode *inode;
+ int err, deleted;
+
+ deleted = file_removed(dentry, NULL);
+ if(deleted < 0)
+ return(ERR_PTR(deleted));
+ else if(deleted)
+ return(ERR_PTR(-ENOENT));
+
+ err = -ENOMEM;
+ parent = HPPFS_I(ino)->proc_dentry;
+ down(&parent->d_inode->i_sem);
+ proc_dentry = d_lookup(parent, &dentry->d_name);
+ if(proc_dentry == NULL){
+ proc_dentry = d_alloc(parent, &dentry->d_name);
+ if(proc_dentry == NULL){
+ up(&parent->d_inode->i_sem);
+ goto out;
+ }
+ new = (*parent->d_inode->i_op->lookup)(parent->d_inode,
+ proc_dentry, NULL);
+ if(new){
+ dput(proc_dentry);
+ proc_dentry = new;
+ }
+ }
+ up(&parent->d_inode->i_sem);
+
+ if(IS_ERR(proc_dentry))
+ return(proc_dentry);
+
+ inode = iget(ino->i_sb, 0);
+ if(inode == NULL)
+ goto out_dput;
+
+ err = init_inode(inode, proc_dentry);
+ if(err)
+ goto out_put;
+
+ hppfs_read_inode(inode);
+
+ d_add(dentry, inode);
+ dentry->d_op = &hppfs_dentry_ops;
+ return(NULL);
+
+ out_put:
+ iput(inode);
+ out_dput:
+ dput(proc_dentry);
+ out:
+ return(ERR_PTR(err));
+}
+
+static struct inode_operations hppfs_file_iops = {
+};
+
+static ssize_t read_proc(struct file *file, char *buf, ssize_t count,
+ loff_t *ppos, int is_user)
+{
+ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+ ssize_t n;
+
+ read = file->f_dentry->d_inode->i_fop->read;
+
+ if(!is_user)
+ set_fs(KERNEL_DS);
+
+ n = (*read)(file, buf, count, &file->f_pos);
+
+ if(!is_user)
+ set_fs(USER_DS);
+
+ if(ppos) *ppos = file->f_pos;
+ return(n);
+}
+
+static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
+{
+ ssize_t n;
+ int cur, err;
+ char *new_buf;
+
+ n = -ENOMEM;
+ new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if(new_buf == NULL){
+ printk("hppfs_read_file : kmalloc failed\n");
+ goto out;
+ }
+ n = 0;
+ while(count > 0){
+ cur = min_t(ssize_t, count, PAGE_SIZE);
+ err = os_read_file(fd, new_buf, cur);
+ if(err < 0){
+ printk("hppfs_read : read failed, errno = %d\n",
+ count);
+ n = err;
+ goto out_free;
+ }
+ else if(err == 0)
+ break;
+
+ if(copy_to_user(buf, new_buf, err)){
+ n = -EFAULT;
+ goto out_free;
+ }
+ n += err;
+ count -= err;
+ }
+ out_free:
+ kfree(new_buf);
+ out:
+ return(n);
+}
+
+static ssize_t hppfs_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct hppfs_private *hppfs = file->private_data;
+ struct hppfs_data *data;
+ loff_t off;
+ int err;
+
+ if(hppfs->contents != NULL){
+ if(*ppos >= hppfs->len) return(0);
+
+ data = hppfs->contents;
+ off = *ppos;
+ while(off >= sizeof(data->contents)){
+ data = list_entry(data->list.next, struct hppfs_data,
+ list);
+ off -= sizeof(data->contents);
+ }
+
+ if(off + count > hppfs->len)
+ count = hppfs->len - off;
+ copy_to_user(buf, &data->contents[off], count);
+ *ppos += count;
+ }
+ else if(hppfs->host_fd != -1){
+ err = os_seek_file(hppfs->host_fd, *ppos);
+ if(err){
+ printk("hppfs_read : seek failed, errno = %d\n", err);
+ return(err);
+ }
+ count = hppfs_read_file(hppfs->host_fd, buf, count);
+ if(count > 0)
+ *ppos += count;
+ }
+ else count = read_proc(hppfs->proc_file, buf, count, ppos, 1);
+
+ return(count);
+}
+
+static ssize_t hppfs_write(struct file *file, const char *buf, size_t len,
+ loff_t *ppos)
+{
+ struct hppfs_private *data = file->private_data;
+ struct file *proc_file = data->proc_file;
+ ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+ int err;
+
+ write = proc_file->f_dentry->d_inode->i_fop->write;
+
+ proc_file->f_pos = file->f_pos;
+ err = (*write)(proc_file, buf, len, &proc_file->f_pos);
+ file->f_pos = proc_file->f_pos;
+
+ return(err);
+}
+
+static int open_host_sock(char *host_file, int *filter_out)
+{
+ char *end;
+ int fd;
+
+ end = &host_file[strlen(host_file)];
+ strcpy(end, "/rw");
+ *filter_out = 1;
+ fd = os_connect_socket(host_file);
+ if(fd > 0)
+ return(fd);
+
+ strcpy(end, "/r");
+ *filter_out = 0;
+ fd = os_connect_socket(host_file);
+ return(fd);
+}
+
+static void free_contents(struct hppfs_data *head)
+{
+ struct hppfs_data *data;
+ struct list_head *ele, *next;
+
+ if(head == NULL) return;
+
+ list_for_each_safe(ele, next, &head->list){
+ data = list_entry(ele, struct hppfs_data, list);
+ kfree(data);
+ }
+ kfree(head);
+}
+
+static struct hppfs_data *hppfs_get_data(int fd, int filter,
+ struct file *proc_file,
+ struct file *hppfs_file,
+ loff_t *size_out)
+{
+ struct hppfs_data *data, *new, *head;
+ int n, err;
+
+ err = -ENOMEM;
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if(data == NULL){
+ printk("hppfs_get_data : head allocation failed\n");
+ goto failed;
+ }
+
+ INIT_LIST_HEAD(&data->list);
+
+ head = data;
+ *size_out = 0;
+
+ if(filter){
+ while((n = read_proc(proc_file, data->contents,
+ sizeof(data->contents), NULL, 0)) > 0)
+ os_write_file(fd, data->contents, n);
+ err = os_shutdown_socket(fd, 0, 1);
+ if(err){
+ printk("hppfs_get_data : failed to shut down "
+ "socket\n");
+ goto failed_free;
+ }
+ }
+ while(1){
+ n = os_read_file(fd, data->contents, sizeof(data->contents));
+ if(n < 0){
+ err = n;
+ printk("hppfs_get_data : read failed, errno = %d\n",
+ err);
+ goto failed_free;
+ }
+ else if(n == 0)
+ break;
+
+ *size_out += n;
+
+ if(n < sizeof(data->contents))
+ break;
+
+ new = kmalloc(sizeof(*data), GFP_KERNEL);
+ if(new == 0){
+ printk("hppfs_get_data : data allocation failed\n");
+ err = -ENOMEM;
+ goto failed_free;
+ }
+
+ INIT_LIST_HEAD(&new->list);
+ list_add(&new->list, &data->list);
+ data = new;
+ }
+ return(head);
+
+ failed_free:
+ free_contents(head);
+ failed:
+ return(ERR_PTR(err));
+}
+
+static struct hppfs_private *hppfs_data(void)
+{
+ struct hppfs_private *data;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if(data == NULL)
+ return(data);
+
+ *data = ((struct hppfs_private ) { .host_fd = -1,
+ .len = -1,
+ .contents = NULL } );
+ return(data);
+}
+
+static int file_mode(int fmode)
+{
+ if(fmode == (FMODE_READ | FMODE_WRITE))
+ return(O_RDWR);
+ if(fmode == FMODE_READ)
+ return(O_RDONLY);
+ if(fmode == FMODE_WRITE)
+ return(O_WRONLY);
+ return(0);
+}
+
+static int hppfs_open(struct inode *inode, struct file *file)
+{
+ struct hppfs_private *data;
+ struct dentry *proc_dentry;
+ char *host_file;
+ int err, fd, type, filter;
+
+ err = -ENOMEM;
+ data = hppfs_data();
+ if(data == NULL)
+ goto out;
+
+ host_file = dentry_name(file->f_dentry, strlen("/rw"));
+ if(host_file == NULL)
+ goto out_free2;
+
+ proc_dentry = HPPFS_I(inode)->proc_dentry;
+
+ /* XXX This isn't closed anywhere */
+ data->proc_file = dentry_open(dget(proc_dentry), NULL,
+ file_mode(file->f_mode));
+ err = PTR_ERR(data->proc_file);
+ if(IS_ERR(data->proc_file))
+ goto out_free1;
+
+ type = os_file_type(host_file);
+ if(type == OS_TYPE_FILE){
+ fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
+ if(fd >= 0)
+ data->host_fd = fd;
+ else printk("hppfs_open : failed to open '%s', errno = %d\n",
+ host_file, -fd);
+
+ data->contents = NULL;
+ }
+ else if(type == OS_TYPE_DIR){
+ fd = open_host_sock(host_file, &filter);
+ if(fd > 0){
+ data->contents = hppfs_get_data(fd, filter,
+ &data->proc_file,
+ file, &data->len);
+ if(!IS_ERR(data->contents))
+ data->host_fd = fd;
+ }
+ else printk("hppfs_open : failed to open a socket in "
+ "'%s', errno = %d\n", host_file, -fd);
+ }
+ kfree(host_file);
+
+ file->private_data = data;
+ return(0);
+
+ out_free1:
+ kfree(host_file);
+ out_free2:
+ free_contents(data->contents);
+ kfree(data);
+ out:
+ return(err);
+}
+
+static int hppfs_dir_open(struct inode *inode, struct file *file)
+{
+ struct hppfs_private *data;
+ struct dentry *proc_dentry;
+ int err;
+
+ err = -ENOMEM;
+ data = hppfs_data();
+ if(data == NULL)
+ goto out;
+
+ proc_dentry = HPPFS_I(inode)->proc_dentry;
+ data->proc_file = dentry_open(dget(proc_dentry), NULL,
+ file_mode(file->f_mode));
+ err = PTR_ERR(data->proc_file);
+ if(IS_ERR(data->proc_file))
+ goto out_free;
+
+ file->private_data = data;
+ return(0);
+
+ out_free:
+ kfree(data);
+ out:
+ return(err);
+}
+
+static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
+{
+ struct hppfs_private *data = file->private_data;
+ struct file *proc_file = &data->proc_file;
+ loff_t (*llseek)(struct file *, loff_t, int);
+ loff_t ret;
+
+ llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
+ if(llseek != NULL){
+ ret = (*llseek)(proc_file, off, where);
+ if(ret < 0)
+ return(ret);
+ }
+
+ return(default_llseek(file, off, where));
+}
+
+static struct file_operations hppfs_file_fops = {
+ .owner = NULL,
+ .llseek = hppfs_llseek,
+ .read = hppfs_read,
+ .write = hppfs_write,
+ .open = hppfs_open,
+};
+
+struct hppfs_dirent {
+ void *vfs_dirent;
+ filldir_t filldir;
+ struct dentry *dentry;
+};
+
+static int hppfs_filldir(void *d, const char *name, int size,
+ loff_t offset, ino_t inode, unsigned int type)
+{
+ struct hppfs_dirent *dirent = d;
+
+ if(file_removed(dirent->dentry, name))
+ return(0);
+
+ return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset,
+ inode, type));
+}
+
+static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
+{
+ struct hppfs_private *data = file->private_data;
+ struct file *proc_file = &data->proc_file;
+ int (*readdir)(struct file *, void *, filldir_t);
+ struct hppfs_dirent dirent = ((struct hppfs_dirent)
+ { .vfs_dirent = ent,
+ .filldir = filldir,
+ .dentry = file->f_dentry } );
+ int err;
+
+ readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
+
+ proc_file->f_pos = file->f_pos;
+ err = (*readdir)(proc_file, &dirent, hppfs_filldir);
+ file->f_pos = proc_file->f_pos;
+
+ return(err);
+}
+
+static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ return(0);
+}
+
+static struct file_operations hppfs_dir_fops = {
+ .owner = NULL,
+ .readdir = hppfs_readdir,
+ .open = hppfs_dir_open,
+ .fsync = hppfs_fsync,
+};
+
+static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf)
+{
+ sf->f_blocks = 0;
+ sf->f_bfree = 0;
+ sf->f_bavail = 0;
+ sf->f_files = 0;
+ sf->f_ffree = 0;
+ sf->f_type = HPPFS_SUPER_MAGIC;
+ return(0);
+}
+
+static struct inode *hppfs_alloc_inode(struct super_block *sb)
+{
+ struct hppfs_inode_info *hi;
+
+ hi = kmalloc(sizeof(*hi), GFP_KERNEL);
+ if(hi == NULL)
+ return(NULL);
+
+ *hi = ((struct hppfs_inode_info) { .proc_dentry = NULL });
+ inode_init_once(&hi->vfs_inode);
+ return(&hi->vfs_inode);
+}
+
+void hppfs_delete_inode(struct inode *ino)
+{
+ clear_inode(ino);
+}
+
+static void hppfs_destroy_inode(struct inode *inode)
+{
+ kfree(HPPFS_I(inode));
+}
+
+static struct super_operations hppfs_sbops = {
+ .alloc_inode = hppfs_alloc_inode,
+ .destroy_inode = hppfs_destroy_inode,
+ .read_inode = hppfs_read_inode,
+ .delete_inode = hppfs_delete_inode,
+ .statfs = hppfs_statfs,
+};
+
+static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+ struct file *proc_file;
+ struct dentry *proc_dentry;
+ int (*readlink)(struct dentry *, char *, int);
+ int err, n;
+
+ proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
+ proc_file = dentry_open(dget(proc_dentry), NULL, O_RDONLY);
+ err = PTR_ERR(proc_dentry);
+ if(IS_ERR(proc_dentry))
+ return(err);
+
+ readlink = proc_dentry->d_inode->i_op->readlink;
+ n = (*readlink)(proc_dentry, buffer, buflen);
+
+ fput(proc_file);
+
+ return(n);
+}
+
+static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct file *proc_file;
+ struct dentry *proc_dentry;
+ int (*follow_link)(struct dentry *, struct nameidata *);
+ int err, n;
+
+ proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
+ proc_file = dentry_open(dget(proc_dentry), NULL, O_RDONLY);
+ err = PTR_ERR(proc_dentry);
+ if(IS_ERR(proc_dentry))
+ return(err);
+
+ follow_link = proc_dentry->d_inode->i_op->follow_link;
+ n = (*follow_link)(proc_dentry, nd);
+
+ fput(proc_file);
+
+ return(n);
+}
+
+static struct inode_operations hppfs_dir_iops = {
+ .lookup = hppfs_lookup,
+};
+
+static struct inode_operations hppfs_link_iops = {
+ .readlink = hppfs_readlink,
+ .follow_link = hppfs_follow_link,
+};
+
+static int init_inode(struct inode *inode, struct dentry *dentry)
+{
+ if(S_ISDIR(dentry->d_inode->i_mode)){
+ inode->i_op = &hppfs_dir_iops;
+ inode->i_fop = &hppfs_dir_fops;
+ }
+ else if(S_ISLNK(dentry->d_inode->i_mode)){
+ inode->i_op = &hppfs_link_iops;
+ inode->i_fop = &hppfs_file_fops;
+ }
+ else {
+ inode->i_op = &hppfs_file_iops;
+ inode->i_fop = &hppfs_file_fops;
+ }
+
+ HPPFS_I(inode)->proc_dentry = dentry;
+
+ return(0);
+}
+
+static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
+{
+ struct inode *root_inode;
+ struct file_system_type *procfs;
+ struct super_block *proc_sb;
+ int err;
+
+ err = -ENOENT;
+ procfs = get_fs_type("proc");
+ if(procfs == NULL)
+ goto out;
+
+ if(list_empty(&procfs->fs_supers))
+ goto out;
+
+ proc_sb = list_entry(procfs->fs_supers.next, struct super_block,
+ s_instances);
+
+ sb->s_blocksize = 1024;
+ sb->s_blocksize_bits = 10;
+ sb->s_magic = HPPFS_SUPER_MAGIC;
+ sb->s_op = &hppfs_sbops;
+
+ root_inode = iget(sb, 0);
+ if(root_inode == NULL)
+ goto out;
+
+ err = init_inode(root_inode, proc_sb->s_root);
+ if(err)
+ goto out_put;
+
+ err = -ENOMEM;
+ sb->s_root = d_alloc_root(root_inode);
+ if(sb->s_root == NULL)
+ goto out_put;
+
+ hppfs_read_inode(root_inode);
+
+ return(0);
+
+ out_put:
+ iput(root_inode);
+ out:
+ return(err);
+}
+
+static struct super_block *hppfs_read_super(struct file_system_type *type,
+ int flags, const char *dev_name,
+ void *data)
+{
+ return(get_sb_nodev(type, flags, data, hppfs_fill_super));
+}
+
+static struct file_system_type hppfs_type = {
+ .owner = THIS_MODULE,
+ .name = "hppfs",
+ .get_sb = hppfs_read_super,
+ .kill_sb = kill_anon_super,
+ .fs_flags = 0,
+};
+
+static int __init init_hppfs(void)
+{
+ return(register_filesystem(&hppfs_type));
+}
+
+static void __exit exit_hppfs(void)
+{
+ unregister_filesystem(&hppfs_type);
+}
+
+module_init(init_hppfs)
+module_exit(exit_hppfs)
+MODULE_LICENSE("GPL");
+
+/*
+ * 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/fs/inode.c b/fs/inode.c
index b87572e8587ed..eab34bcf84ab1 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1373,8 +1373,7 @@ void __init inode_init(unsigned long mempages)
/* inode slab cache */
inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, init_once,
- NULL);
+ 0, SLAB_PANIC, init_once, NULL);
set_shrinker(DEFAULT_SEEKS, shrink_icache_memory);
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 491dcde30a0e4..0ee7beb9d48ad 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -108,7 +108,7 @@ static int init_inodecache(void)
{
isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
sizeof(struct iso_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (isofs_inode_cachep == NULL)
return -ENOMEM;
@@ -715,6 +715,7 @@ root_found:
}
s->s_magic = ISOFS_SUPER_MAGIC;
+ s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */
/* The CDROM is read-only, has no nodes (devices) on it, and since
all of the files appear to be owned by root, we really do not want
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index c37fb163ef811..3bc1b92b450b4 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -302,7 +302,7 @@ static int __init init_jffs2_fs(void)
jffs2_inode_cachep = kmem_cache_create("jffs2_i",
sizeof(struct jffs2_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
jffs2_i_init_once, NULL);
if (!jffs2_inode_cachep) {
printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 9615a83d7ef01..f7ed6ad08af0f 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -58,7 +58,7 @@ DECLARE_COMPLETION(jfsIOwait);
#ifdef CONFIG_JFS_DEBUG
int jfsloglevel = JFS_LOGLEVEL_WARN;
-module_param(jfsloglevel, int, 644);
+module_param(jfsloglevel, int, 0644);
MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
#endif
diff --git a/fs/libfs.c b/fs/libfs.c
index 205cfdbe2bc11..5d3f82bbc8b81 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -27,14 +27,27 @@ int simple_statfs(struct super_block *sb, struct kstatfs *buf)
}
/*
- * Lookup the data. This is trivial - if the dentry didn't already
- * exist, we know it is negative.
+ * Retaining negative dentries for an in-memory filesystem just wastes
+ * memory and lookup time: arrange for them to be deleted immediately.
*/
+static int simple_delete_dentry(struct dentry *dentry)
+{
+ return 1;
+}
+/*
+ * Lookup the data. This is trivial - if the dentry didn't already
+ * exist, we know it is negative. Set d_op to delete negative dentries.
+ */
struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
+ static struct dentry_operations simple_dentry_operations = {
+ .d_delete = simple_delete_dentry,
+ };
+
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
+ dentry->d_op = &simple_dentry_operations;
d_add(dentry, NULL);
return NULL;
}
@@ -456,6 +469,58 @@ ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos,
return count;
}
+/*
+ * Transaction based IO.
+ * The file expects a single write which triggers the transaction, and then
+ * possibly a read which collects the result - which is stored in a
+ * file-local buffer.
+ */
+char *simple_transaction_get(struct file *file, const char __user *buf, size_t size)
+{
+ struct simple_transaction_argresp *ar;
+ static spinlock_t simple_transaction_lock = SPIN_LOCK_UNLOCKED;
+
+ if (size > SIMPLE_TRANSACTION_LIMIT - 1)
+ return ERR_PTR(-EFBIG);
+
+ ar = (struct simple_transaction_argresp *)get_zeroed_page(GFP_KERNEL);
+ if (!ar)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock(&simple_transaction_lock);
+
+ /* only one write allowed per open */
+ if (file->private_data) {
+ spin_unlock(&simple_transaction_lock);
+ free_page((unsigned long)ar);
+ return ERR_PTR(-EBUSY);
+ }
+
+ file->private_data = ar;
+
+ spin_unlock(&simple_transaction_lock);
+
+ if (copy_from_user(ar->data, buf, size))
+ return ERR_PTR(-EFAULT);
+
+ return ar->data;
+}
+
+ssize_t simple_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
+{
+ struct simple_transaction_argresp *ar = file->private_data;
+
+ if (!ar)
+ return 0;
+ return simple_read_from_buffer(buf, size, pos, ar->data, ar->size);
+}
+
+int simple_transaction_release(struct inode *inode, struct file *file)
+{
+ free_page((unsigned long)file->private_data);
+ return 0;
+}
+
EXPORT_SYMBOL(dcache_dir_close);
EXPORT_SYMBOL(dcache_dir_lseek);
EXPORT_SYMBOL(dcache_dir_open);
@@ -479,3 +544,6 @@ EXPORT_SYMBOL(simple_statfs);
EXPORT_SYMBOL(simple_sync_file);
EXPORT_SYMBOL(simple_unlink);
EXPORT_SYMBOL(simple_read_from_buffer);
+EXPORT_SYMBOL(simple_transaction_get);
+EXPORT_SYMBOL(simple_transaction_read);
+EXPORT_SYMBOL(simple_transaction_release);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 47c77137b042e..1bc0676a4f807 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -409,13 +409,13 @@ MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
MODULE_LICENSE("GPL");
module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong,
- &nlm_grace_period, 644);
+ &nlm_grace_period, 0644);
module_param_call(nlm_timeout, param_set_timeout, param_get_ulong,
- &nlm_timeout, 644);
+ &nlm_timeout, 0644);
module_param_call(nlm_udpport, param_set_port, param_get_int,
- &nlm_udpport, 644);
+ &nlm_udpport, 0644);
module_param_call(nlm_tcpport, param_set_port, param_get_int,
- &nlm_tcpport, 644);
+ &nlm_tcpport, 0644);
/*
* Initialising and terminating the module.
diff --git a/fs/locks.c b/fs/locks.c
index df4060fc630d4..596119474493d 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2063,4 +2063,4 @@ static int __init filelock_init(void)
return 0;
}
-module_init(filelock_init)
+core_initcall(filelock_init);
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 9295de94df66a..e93ebd55f8618 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -79,7 +79,7 @@ static int init_inodecache(void)
{
minix_inode_cachep = kmem_cache_create("minix_inode_cache",
sizeof(struct minix_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (minix_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/mpage.c b/fs/mpage.c
index 078d0c97e1c5c..4bbf15ee91fe0 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -290,7 +290,8 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
alloc_new:
if (bio == NULL) {
bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
- nr_pages, GFP_KERNEL);
+ min_t(int, nr_pages, bio_get_nr_vecs(bdev)),
+ GFP_KERNEL);
if (bio == NULL)
goto confused;
}
diff --git a/fs/namei.c b/fs/namei.c
index f3ee9dbe22af3..a01e3ca1ef2e2 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1094,8 +1094,12 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
static inline int may_delete(struct inode *dir,struct dentry *victim,int isdir)
{
int error;
- if (!victim->d_inode || victim->d_parent->d_inode != dir)
+
+ if (!victim->d_inode)
return -ENOENT;
+
+ BUG_ON(victim->d_parent->d_inode != dir);
+
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
if (error)
return error;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index c1745b6f1a3ef..4947d9b11fc13 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -115,11 +115,6 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (!ncp_conn_valid(NCP_SERVER(inode)))
return -EIO;
- if (!S_ISREG(inode->i_mode)) {
- DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
- inode->i_mode);
- return -EINVAL;
- }
pos = *ppos;
@@ -175,10 +170,8 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
*ppos = pos;
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- }
-
+ file_accessed(file);
+
DPRINTK("ncp_file_read: exit %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
@@ -201,11 +194,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
dentry->d_parent->d_name.name, dentry->d_name.name);
if (!ncp_conn_valid(NCP_SERVER(inode)))
return -EIO;
- if (!S_ISREG(inode->i_mode)) {
- DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
- inode->i_mode);
- return -EINVAL;
- }
if ((ssize_t) count < 0)
return -EINVAL;
pos = *ppos;
@@ -273,8 +261,9 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
}
}
vfree(bouncebuffer);
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
-
+
+ inode_update_time(inode, 1);
+
*ppos = pos;
if (pos > inode->i_size) {
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index bea651fd2f943..8e64b6759a2d4 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -72,7 +72,7 @@ static int init_inodecache(void)
{
ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
sizeof(struct ncp_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (ncp_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 5fb8e87164873..52d60c3d89962 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -110,23 +110,19 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
DPRINTK("ncp_mmap: called\n");
- if (!ncp_conn_valid(NCP_SERVER(inode))) {
+ if (!ncp_conn_valid(NCP_SERVER(inode)))
return -EIO;
- }
+
/* only PAGE_COW or read-only supported now */
if (vma->vm_flags & VM_SHARED)
return -EINVAL;
- if (!inode->i_sb || !S_ISREG(inode->i_mode))
- return -EACCES;
/* we do not support files bigger than 4GB... We eventually
supports just 4GB... */
if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff
> (1U << (32 - PAGE_SHIFT)))
return -EFBIG;
- if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- }
vma->vm_ops = &ncp_file_mmap;
+ file_accessed(file);
return 0;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 243b5750287ae..fb627a12d53b2 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1859,7 +1859,7 @@ int nfs_init_inodecache(void)
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (nfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index fe679026da7db..8646159168625 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -495,8 +495,10 @@ static int __init root_nfs_get_handle(void)
if (status < 0)
printk(KERN_ERR "Root-NFS: Server returned error %d "
"while mounting %s\n", status, nfs_path);
- else
- nfs_copy_fh(nfs_data.root, fh);
+ else {
+ nfs_data.root.size = fh.size;
+ memcpy(nfs_data.root.data, fh.data, fh.size);
+ }
return status;
}
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 3b9e865c4abc1..1a53ff65dc3f7 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -294,6 +294,11 @@ void svc_export_request(struct cache_detail *cd,
qword_add(bpp, blen, exp->ex_client->name);
pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen);
+ if (IS_ERR(pth)) {
+ /* is this correct? */
+ (*bpp)[0] = '\n';
+ return;
+ }
qword_add(bpp, blen, pth);
(*bpp)[-1] = '\n';
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 9c9399258afd0..161afdcb8f7d9 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -80,101 +80,31 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Leasetime] = write_leasetime,
};
-/* an argresp is stored in an allocated page and holds the
- * size of the argument or response, along with its content
- */
-struct argresp {
- ssize_t size;
- char data[0];
-};
-
-/*
- * transaction based IO methods.
- * The file expects a single write which triggers the transaction, and then
- * possibly a read which collects the result - which is stored in a
- * file-local buffer.
- */
-static ssize_t TA_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
+static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
ino_t ino = file->f_dentry->d_inode->i_ino;
- struct argresp *ar;
- ssize_t rv = 0;
+ char *data;
+ ssize_t rv;
if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino])
return -EINVAL;
- if (file->private_data)
- return -EINVAL; /* only one write allowed per open */
- if (size > PAGE_SIZE - sizeof(struct argresp))
- return -EFBIG;
- ar = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!ar)
- return -ENOMEM;
- ar->size = 0;
- down(&file->f_dentry->d_inode->i_sem);
- if (file->private_data)
- rv = -EINVAL;
- else
- file->private_data = ar;
- up(&file->f_dentry->d_inode->i_sem);
- if (rv) {
- kfree(ar);
- return rv;
- }
- if (copy_from_user(ar->data, buf, size))
- return -EFAULT;
-
- rv = write_op[ino](file, ar->data, size);
+ data = simple_transaction_get(file, buf, size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ rv = write_op[ino](file, data, size);
if (rv>0) {
- ar->size = rv;
+ simple_transaction_set(file, rv);
rv = size;
}
return rv;
}
-
-static ssize_t TA_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
-{
- struct argresp *ar;
- ssize_t rv = 0;
-
- if (file->private_data == NULL)
- rv = TA_write(file, buf, 0, pos);
- if (rv < 0)
- return rv;
-
- ar = file->private_data;
- if (!ar)
- return 0;
- if (*pos >= ar->size)
- return 0;
- if (*pos + size > ar->size)
- size = ar->size - *pos;
- if (copy_to_user(buf, ar->data + *pos, size))
- return -EFAULT;
- *pos += size;
- return size;
-}
-
-static int TA_open(struct inode *inode, struct file *file)
-{
- file->private_data = NULL;
- return 0;
-}
-
-static int TA_release(struct inode *inode, struct file *file)
-{
- void *p = file->private_data;
- file->private_data = NULL;
- kfree(p);
- return 0;
-}
-
static struct file_operations transaction_ops = {
- .write = TA_write,
- .read = TA_read,
- .open = TA_open,
- .release = TA_release,
+ .write = nfsctl_transaction_write,
+ .read = simple_transaction_read,
+ .release = simple_transaction_release,
};
extern struct seq_operations nfs_exports_op;
@@ -366,7 +296,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
if (len)
return len;
- mesg = buf; len = PAGE_SIZE-sizeof(struct argresp);
+ mesg = buf; len = SIMPLE_TRANSACTION_LIMIT;
qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
mesg[-1] = '\n';
return mesg - buf;
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index ba072f58a2e98..faaccbe16b690 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2638,7 +2638,7 @@ static int __init init_ntfs_fs(void)
ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
sizeof(ntfs_inode), 0,
- SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, NULL, NULL);
+ SLAB_RECLAIM_ACCOUNT, NULL, NULL);
if (!ntfs_inode_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_inode_cache_name);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 995080fd88d23..d41a679d13625 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -316,11 +316,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
state = *get_task_state(task);
vsize = eip = esp = 0;
- task_lock(task);
- mm = task->mm;
- if(mm)
- mm = mmgrab(mm);
- task_unlock(task);
+ mm = get_task_mm(task);
if (mm) {
down_read(&mm->mmap_sem);
vsize = task_vsize(mm);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 0b70c615bac30..a3614e9910aa5 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -60,6 +60,9 @@ enum pid_directory_inos {
PROC_TGID_MAPS,
PROC_TGID_MOUNTS,
PROC_TGID_WCHAN,
+#ifdef CONFIG_SCHEDSTATS
+ PROC_TGID_SCHEDSTAT,
+#endif
#ifdef CONFIG_SECURITY
PROC_TGID_ATTR,
PROC_TGID_ATTR_CURRENT,
@@ -83,6 +86,9 @@ enum pid_directory_inos {
PROC_TID_MAPS,
PROC_TID_MOUNTS,
PROC_TID_WCHAN,
+#ifdef CONFIG_SCHEDSTATS
+ PROC_TID_SCHEDSTAT,
+#endif
#ifdef CONFIG_SECURITY
PROC_TID_ATTR,
PROC_TID_ATTR_CURRENT,
@@ -123,6 +129,9 @@ static struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_KALLSYMS
E(PROC_TGID_WCHAN, "wchan", S_IFREG|S_IRUGO),
#endif
+#ifdef CONFIG_SCHEDSTATS
+ E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO),
+#endif
{0,0,NULL,0}
};
static struct pid_entry tid_base_stuff[] = {
@@ -145,6 +154,9 @@ static struct pid_entry tid_base_stuff[] = {
#ifdef CONFIG_KALLSYMS
E(PROC_TID_WCHAN, "wchan", S_IFREG|S_IRUGO),
#endif
+#ifdef CONFIG_SCHEDSTATS
+ E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO),
+#endif
{0,0,NULL,0}
};
@@ -340,7 +352,7 @@ static int proc_pid_cmdline(struct task_struct *task, char * buffer)
// If the nul at the end of args has been overwritten, then
// assume application is using setproctitle(3).
- if (res > 0 && buffer[res-1] != '\0') {
+ if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
len = strnlen(buffer, res);
if (len < res) {
res = len;
@@ -398,6 +410,19 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
}
#endif /* CONFIG_KALLSYMS */
+#ifdef CONFIG_SCHEDSTATS
+/*
+ * Provides /proc/PID/schedstat
+ */
+static int proc_pid_schedstat(struct task_struct *task, char *buffer)
+{
+ return sprintf(buffer, "%lu %lu %lu\n",
+ task->sched_info.cpu_time,
+ task->sched_info.run_delay,
+ task->sched_info.pcnt);
+}
+#endif
+
/************************************************************************/
/* Here the fs part begins */
/************************************************************************/
@@ -518,7 +543,6 @@ static ssize_t proc_info_read(struct file * file, char __user * buf,
struct inode * inode = file->f_dentry->d_inode;
unsigned long page;
ssize_t length;
- ssize_t end;
struct task_struct *task = proc_task(inode);
if (count > PROC_BLOCK_SIZE)
@@ -528,24 +552,10 @@ static ssize_t proc_info_read(struct file * file, char __user * buf,
length = PROC_I(inode)->op.proc_read(task, (char*)page);
- if (length < 0) {
- free_page(page);
- return length;
- }
- /* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
- free_page(page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- if (copy_to_user(buf, (char *) page + *ppos, count))
- count = -EFAULT;
- else
- *ppos = end;
+ if (length >= 0)
+ length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
free_page(page);
- return count;
+ return length;
}
static struct file_operations proc_info_file_operations = {
@@ -1169,7 +1179,6 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
struct inode * inode = file->f_dentry->d_inode;
unsigned long page;
ssize_t length;
- ssize_t end;
struct task_struct *task = proc_task(inode);
if (count > PAGE_SIZE)
@@ -1180,24 +1189,10 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
length = security_getprocattr(task,
(char*)file->f_dentry->d_name.name,
(void*)page, count);
- if (length < 0) {
- free_page(page);
- return length;
- }
- /* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
- free_page(page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- if (copy_to_user(buf, (char *) page + *ppos, count))
- count = -EFAULT;
- else
- *ppos = end;
+ if (length >= 0)
+ length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
free_page(page);
- return count;
+ return length;
}
static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
@@ -1376,6 +1371,13 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
ei->op.proc_read = proc_pid_wchan;
break;
#endif
+#ifdef CONFIG_SCHEDSTATS
+ case PROC_TID_SCHEDSTAT:
+ case PROC_TGID_SCHEDSTAT:
+ inode->i_fop = &proc_info_file_operations;
+ ei->op.proc_read = proc_pid_schedstat;
+ break;
+#endif
default:
printk("procfs: impossible type (%d)",p->type);
iput(inode);
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 2d38f02c9e4eb..d8d976d5f39ad 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -120,7 +120,7 @@ int __init proc_init_inodecache(void)
{
proc_inode_cachep = kmem_cache_create("proc_inode_cache",
sizeof(struct proc_inode),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (proc_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 415d6ee489b45..e0733123f5aba 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -681,6 +681,9 @@ void __init proc_misc_init(void)
#ifdef CONFIG_MODULES
create_seq_entry("modules", 0, &proc_modules_operations);
#endif
+#ifdef CONFIG_SCHEDSTATS
+ create_seq_entry("schedstat", 0, &proc_schedstat_operations);
+#endif
#ifdef CONFIG_PROC_KCORE
proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
if (proc_root_kcore) {
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 19b7d5a053e19..ed36a8bb72cd9 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -544,7 +544,7 @@ static int init_inodecache(void)
{
qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache",
sizeof(struct qnx4_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (qnx4_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index a7e9e643ad332..966d1adb07ffb 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -444,7 +444,7 @@ static int init_inodecache(void)
{
reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
sizeof(struct reiserfs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (reiserfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 7ef7b4545d395..21ba7189ec322 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -761,6 +761,11 @@ reiserfs_xattr_del (struct inode *inode, const char *name)
err = __reiserfs_xattr_del (dir, name, strlen (name));
dput (dir);
+ if (!err) {
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty (inode);
+ }
+
out:
return err;
}
@@ -1240,8 +1245,10 @@ xattr_lookup_poison (struct dentry *dentry, struct qstr *q1, struct qstr *name)
name->hash == priv_root->d_name.hash &&
!memcmp (name->name, priv_root->d_name.name, name->len)) {
return -ENOENT;
- }
- return 0;
+ } else if (q1->len == name->len &&
+ !memcmp(q1->name, name->name, name->len))
+ return 0;
+ return 1;
}
static struct dentry_operations xattr_lookup_poison_ops = {
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index 623139f062d3f..a1daab81c8301 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -289,8 +289,14 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
error = reiserfs_xattr_set(inode, name, value, size, 0);
} else {
error = reiserfs_xattr_del (inode, name);
- if (error == -ENODATA)
+ if (error == -ENODATA) {
+ /* This may seem odd here, but it means that the ACL was set
+ * with a value representable with mode bits. If there was
+ * an ACL before, reiserfs_xattr_del already dirtied the inode.
+ */
+ mark_inode_dirty (inode);
error = 0;
+ }
}
if (value)
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 28c863a2e47e8..3611cc0df95a8 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -579,7 +579,7 @@ static int init_inodecache(void)
{
romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
sizeof(struct romfs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (romfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index c8ca98ab273e2..1001a64b35da5 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -80,7 +80,7 @@ static int init_inodecache(void)
{
smb_inode_cachep = kmem_cache_create("smb_inode_cache",
sizeof(struct smb_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (smb_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 2be44b7a9f74d..45e077653a1d8 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -340,7 +340,7 @@ int __init sysv_init_icache(void)
{
sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
sizeof(struct sysv_inode_info), 0,
- SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (!sysv_inode_cachep)
return -ENOMEM;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index eff7d84724160..c132a95052f76 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -145,7 +145,7 @@ static int init_inodecache(void)
{
udf_inode_cachep = kmem_cache_create("udf_inode_cache",
sizeof(struct udf_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (udf_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 43475183b12d2..e2c45d0e2cfa7 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1183,7 +1183,7 @@ static int init_inodecache(void)
{
ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
sizeof(struct ufs_inode_info),
- 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (ufs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index eca2c32f8be8a..4b2d0829fc6ac 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -259,7 +259,7 @@ linvfs_sendfile(
loff_t *ppos,
size_t count,
read_actor_t actor,
- void __user *target)
+ void *target)
{
vnode_t *vp = LINVFS_GET_VP(filp->f_dentry->d_inode);
ssize_t rval;
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index ae16c6f959c08..39b3cd5f51d8e 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -366,7 +366,7 @@ xfs_sendfile(
int ioflags,
size_t count,
read_actor_t actor,
- void __user *target,
+ void *target,
cred_t *credp)
{
ssize_t ret;
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h
index d33af13308e59..d723e35254a0b 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.h
+++ b/fs/xfs/linux-2.6/xfs_lrw.h
@@ -104,7 +104,7 @@ extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *,
loff_t *, int, struct cred *);
extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *,
loff_t *, int, size_t, read_actor_t,
- void __user *, struct cred *);
+ void *, struct cred *);
extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index fc7d4ce32f088..3737a1cf66386 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -335,8 +335,7 @@ STATIC int
init_inodecache( void )
{
linvfs_inode_zone = kmem_cache_create("linvfs_icache",
- sizeof(vnode_t), 0,
- SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+ sizeof(vnode_t), 0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (linvfs_inode_zone == NULL)
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 33c89a6e63881..c274b7f589e46 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -192,7 +192,7 @@ typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *,
loff_t *, int, struct cred *);
typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *,
loff_t *, int, size_t, read_actor_t,
- void __user *, struct cred *);
+ void *, struct cred *);
typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *,
int, unsigned int, void __user *);
typedef int (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int,
diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h
index b316fc6a0f718..56006caed0fb8 100644
--- a/include/asm-alpha/page.h
+++ b/include/asm-alpha/page.h
@@ -1,6 +1,7 @@
#ifndef _ALPHA_PAGE_H
#define _ALPHA_PAGE_H
+#include <linux/config.h>
#include <asm/pal.h>
/* PAGE_SHIFT determines the page size */
diff --git a/include/asm-arm/arch-rpc/io.h b/include/asm-arm/arch-rpc/io.h
index 3f7a2366cad32..939aa6a605f82 100644
--- a/include/asm-arm/arch-rpc/io.h
+++ b/include/asm-arm/arch-rpc/io.h
@@ -22,40 +22,40 @@
*/
#define __arch_base_getb(b,o) \
({ \
- unsigned int v, r = (b); \
+ unsigned int __v, __r = (b); \
__asm__ __volatile__( \
"ldrb %0, [%1, %2]" \
- : "=r" (v) \
- : "r" (r), "Ir" (o)); \
- v; \
+ : "=r" (__v) \
+ : "r" (__r), "Ir" (o)); \
+ __v; \
})
#define __arch_base_getl(b,o) \
({ \
- unsigned int v, r = (b); \
+ unsigned int __v, __r = (b); \
__asm__ __volatile__( \
"ldr %0, [%1, %2]" \
- : "=r" (v) \
- : "r" (r), "Ir" (o)); \
- v; \
+ : "=r" (__v) \
+ : "r" (__r), "Ir" (o)); \
+ __v; \
})
#define __arch_base_putb(v,b,o) \
({ \
- unsigned int r = (b); \
+ unsigned int __r = (b); \
__asm__ __volatile__( \
"strb %0, [%1, %2]" \
: \
- : "r" (v), "r" (r), "Ir" (o)); \
+ : "r" (v), "r" (__r), "Ir" (o));\
})
#define __arch_base_putl(v,b,o) \
({ \
- unsigned int r = (b); \
+ unsigned int __r = (b); \
__asm__ __volatile__( \
"str %0, [%1, %2]" \
: \
- : "r" (v), "r" (r), "Ir" (o)); \
+ : "r" (v), "r" (__r), "Ir" (o));\
})
/*
@@ -176,15 +176,15 @@ DECLARE_IO(int,l,"")
#define __outwc(value,port) \
({ \
- unsigned long v = value; \
+ unsigned long __v = value; \
if (__PORT_PCIO((port))) \
__asm__ __volatile__( \
"str %0, [%1, %2] @ outwc" \
- : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
+ : : "r" (__v|__v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
else \
__asm__ __volatile__( \
"str %0, [%1, %2] @ outwc" \
- : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2)); \
+ : : "r" (__v|__v<<16), "r" (IO_BASE), "r" ((port) << 2)); \
})
#define __inwc(port) \
@@ -203,15 +203,15 @@ DECLARE_IO(int,l,"")
#define __outlc(value,port) \
({ \
- unsigned long v = value; \
+ unsigned long __v = value; \
if (__PORT_PCIO((port))) \
__asm__ __volatile__( \
"str %0, [%1, %2] @ outlc" \
- : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
+ : : "r" (__v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
else \
__asm__ __volatile__( \
"str %0, [%1, %2] @ outlc" \
- : : "r" (v), "r" (IO_BASE), "r" ((port) << 2)); \
+ : : "r" (__v), "r" (IO_BASE), "r" ((port) << 2)); \
})
#define __inlc(port) \
@@ -250,6 +250,6 @@ DECLARE_IO(int,l,"")
/*
* 1:1 mapping for ioremapped regions.
*/
-#define __mem_pci(x) (x)
+#define __mem_pci(x) ((unsigned long)(x))
#endif
diff --git a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h
index cb8c5257d25f2..f5b478f16a526 100644
--- a/include/asm-arm/hardirq.h
+++ b/include/asm-arm/hardirq.h
@@ -22,12 +22,20 @@ typedef struct {
*
* - bits 0-7 are the preemption count (max depth: 256)
* - bits 8-15 are the softirq count (max # of softirqs: 256)
- * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ * - bits 16-24 are the hardirq count (max # of hardirqs: 512)
* - bit 26 is the PREEMPT_ACTIVE flag
+ *
+ * We optimize HARDIRQ_BITS for immediate constant, and only
+ * increase it if really needed.
*/
#define PREEMPT_BITS 8
#define SOFTIRQ_BITS 8
+
+#if NR_IRQS > 256
+#define HARDIRQ_BITS 9
+#else
#define HARDIRQ_BITS 8
+#endif
#define PREEMPT_SHIFT 0
#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h
index 237862bf65686..3225380694dd1 100644
--- a/include/asm-arm/memory.h
+++ b/include/asm-arm/memory.h
@@ -186,8 +186,8 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
*/
#ifndef __arch_page_to_dma
#define page_to_dma(dev, page) ((dma_addr_t)__virt_to_bus((unsigned long)page_address(page)))
-#define dma_to_virt(dev, addr) (__bus_to_virt(addr))
-#define virt_to_dma(dev, addr) (__virt_to_bus((unsigned long)(addr)))
+#define dma_to_virt(dev, addr) ((void *)__bus_to_virt(addr))
+#define virt_to_dma(dev, addr) ((dma_addr_t)__virt_to_bus((unsigned long)(addr)))
#else
#define page_to_dma(dev, page) (__arch_page_to_dma(dev, page))
#define dma_to_virt(dev, addr) (__arch_dma_to_virt(dev, addr))
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 655cb5d01eda0..f223def885b27 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -57,6 +57,13 @@
/* Kernel symbol table: strings */ \
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
+ } \
+ \
+ /* Built-in module parameters. */ \
+ __param : AT(ADDR(__param) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___param) = .; \
+ *(__param) \
+ VMLINUX_SYMBOL(__stop___param) = .; \
}
#define SECURITY_INIT \
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 8fd938fa98868..9db0b712d57a7 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -31,6 +31,11 @@
*
* This function is atomic and may not be reordered. See __set_bit()
* if you do not require the atomic guarantees.
+ *
+ * Note: there are no guarantees that this function will not be reordered
+ * on non x86 architectures, so if you are writting portable code,
+ * make sure not to rely on its reordering guarantees.
+ *
* Note that @nr may be almost arbitrarily large; this function is not
* restricted to acting on a single-word quantity.
*/
@@ -109,7 +114,8 @@ static inline void __change_bit(int nr, volatile unsigned long * addr)
* @nr: Bit to change
* @addr: Address to start counting from
*
- * change_bit() is atomic and may not be reordered.
+ * change_bit() is atomic and may not be reordered. It may be
+ * reordered on other architectures than x86.
* Note that @nr may be almost arbitrarily large; this function is not
* restricted to acting on a single-word quantity.
*/
@@ -127,6 +133,7 @@ static inline void change_bit(int nr, volatile unsigned long * addr)
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
+ * It may be reordered on other architectures than x86.
* It also implies a memory barrier.
*/
static inline int test_and_set_bit(int nr, volatile unsigned long * addr)
@@ -165,7 +172,8 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long * addr)
* @nr: Bit to clear
* @addr: Address to count from
*
- * This operation is atomic and cannot be reordered.
+ * This operation is atomic and cannot be reordered.
+ * It can be reorderdered on other architectures other than x86.
* It also implies a memory barrier.
*/
static inline int test_and_clear_bit(int nr, volatile unsigned long * addr)
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index d6005e6e80068..fdbd65ca669e6 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -71,9 +71,13 @@
#define X86_FEATURE_P4 (3*32+ 7) /* P4 */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
-
+#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */
+#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_CID (4*32+10) /* Context ID */
+#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */
@@ -92,13 +96,14 @@
#define cpu_has_tsc boot_cpu_has(X86_FEATURE_TSC)
#define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE)
#define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE)
-#define cpu_has_sse2 boot_cpu_has(X86_FEATURE_XMM2)
#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
#define cpu_has_sep boot_cpu_has(X86_FEATURE_SEP)
#define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR)
#define cpu_has_mmx boot_cpu_has(X86_FEATURE_MMX)
#define cpu_has_fxsr boot_cpu_has(X86_FEATURE_FXSR)
#define cpu_has_xmm boot_cpu_has(X86_FEATURE_XMM)
+#define cpu_has_xmm2 boot_cpu_has(X86_FEATURE_XMM2)
+#define cpu_has_xmm3 boot_cpu_has(X86_FEATURE_XMM3)
#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT)
#define cpu_has_mp boot_cpu_has(X86_FEATURE_MP)
#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX)
@@ -106,7 +111,9 @@
#define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR)
#define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
#define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE)
+#define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN)
#define cpu_has_xcrypt boot_cpu_has(X86_FEATURE_XCRYPT)
+#define cpu_has_xcrypt_enabled boot_cpu_has(X86_FEATURE_XCRYPT_EN)
#endif /* __ASM_I386_CPUFEATURE_H */
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 791faa169b836..805a0dd16f052 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -14,6 +14,15 @@
#define _ASM_FIXMAP_H
#include <linux/config.h>
+
+/* used by vmalloc.c, vsyscall.lds.S.
+ *
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap.
+ */
+#define __FIXADDR_TOP 0xfffff000
+
+#ifndef __ASSEMBLY__
#include <linux/kernel.h>
#include <asm/acpi.h>
#include <asm/apicdef.h>
@@ -97,13 +106,8 @@ extern void __set_fixmap (enum fixed_addresses idx,
#define clear_fixmap(idx) \
__set_fixmap(idx, 0, __pgprot(0))
-/*
- * used by vmalloc.c.
- *
- * Leave one empty page between vmalloc'ed areas and
- * the start of the fixmap.
- */
-#define FIXADDR_TOP (0xfffff000UL)
+#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
+
#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
@@ -148,4 +152,5 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
return __virt_to_fix(vaddr);
}
+#endif /* !__ASSEMBLY__ */
#endif
diff --git a/include/asm-i386/mach-bigsmp/mach_ipi.h b/include/asm-i386/mach-bigsmp/mach_ipi.h
index 4cb4ba486362d..9404c535b7ecb 100644
--- a/include/asm-i386/mach-bigsmp/mach_ipi.h
+++ b/include/asm-i386/mach-bigsmp/mach_ipi.h
@@ -1,7 +1,7 @@
#ifndef __ASM_MACH_IPI_H
#define __ASM_MACH_IPI_H
-inline void send_IPI_mask_sequence(cpumask_t mask, int vector);
+void send_IPI_mask_sequence(cpumask_t mask, int vector);
static inline void send_IPI_mask(cpumask_t mask, int vector)
{
diff --git a/include/asm-i386/mach-es7000/mach_ipi.h b/include/asm-i386/mach-es7000/mach_ipi.h
index cb8a2fdb5c599..5e61bd220b06c 100644
--- a/include/asm-i386/mach-es7000/mach_ipi.h
+++ b/include/asm-i386/mach-es7000/mach_ipi.h
@@ -1,7 +1,7 @@
#ifndef __ASM_MACH_IPI_H
#define __ASM_MACH_IPI_H
-inline void send_IPI_mask_sequence(cpumask_t mask, int vector);
+void send_IPI_mask_sequence(cpumask_t mask, int vector);
static inline void send_IPI_mask(cpumask_t mask, int vector)
{
diff --git a/include/asm-i386/mach-summit/mach_ipi.h b/include/asm-i386/mach-summit/mach_ipi.h
index 4cb4ba486362d..9404c535b7ecb 100644
--- a/include/asm-i386/mach-summit/mach_ipi.h
+++ b/include/asm-i386/mach-summit/mach_ipi.h
@@ -1,7 +1,7 @@
#ifndef __ASM_MACH_IPI_H
#define __ASM_MACH_IPI_H
-inline void send_IPI_mask_sequence(cpumask_t mask, int vector);
+void send_IPI_mask_sequence(cpumask_t mask, int vector);
static inline void send_IPI_mask(cpumask_t mask, int vector)
{
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index eb0e11f106830..fc3fb25278de0 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -116,6 +116,8 @@ static __inline__ int get_order(unsigned long size)
return order;
}
+extern int sysctl_legacy_va_layout;
+
#endif /* __ASSEMBLY__ */
#ifdef __ASSEMBLY__
diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
index de51110560b9d..58867b62f47b4 100644
--- a/include/asm-i386/pgtable-2level.h
+++ b/include/asm-i386/pgtable-2level.h
@@ -75,4 +75,11 @@ static inline int pte_exec_kernel(pte_t pte)
#define pgoff_to_pte(off) \
((pte_t) { (((off) & 0x1f) << 1) + (((off) >> 5) << 8) + _PAGE_FILE })
+/* Encode and de-code a swap entry */
+#define __swp_type(x) (((x).val >> 1) & 0x1f)
+#define __swp_offset(x) ((x).val >> 8)
+#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
+
#endif /* _I386_PGTABLE_2LEVEL_H */
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
index d78e3493da720..e48ab3d07c834 100644
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -134,4 +134,11 @@ static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
#define pgoff_to_pte(off) ((pte_t) { _PAGE_FILE, (off) })
#define PTE_FILE_MAX_BITS 32
+/* Encode and de-code a swap entry */
+#define __swp_type(x) (((x).val) & 0x1f)
+#define __swp_offset(x) ((x).val >> 5)
+#define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) << 5})
+#define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high })
+#define __swp_entry_to_pte(x) ((pte_t){ 0, (x).val })
+
#endif /* _I386_PGTABLE_3LEVEL_H */
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index 8f9fcab61f5cc..b4ba1fd6f99dc 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -398,13 +398,6 @@ extern pte_t *lookup_address(unsigned long address);
} \
} while (0)
-/* Encode and de-code a swap entry */
-#define __swp_type(x) (((x).val >> 1) & 0x1f)
-#define __swp_offset(x) ((x).val >> 8)
-#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
-#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
-#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
-
#endif /* !__ASSEMBLY__ */
#ifndef CONFIG_DISCONTIGMEM
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index b542bd9d5a2b7..5c1a6c65fbdfa 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -297,6 +297,8 @@ extern unsigned int mca_pentium_flag;
*/
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
/*
* Size of io_bitmap.
*/
@@ -647,9 +649,4 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c);
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
-#ifdef CONFIG_SCHED_SMT
-#define ARCH_HAS_SCHED_DOMAIN
-#define ARCH_HAS_SCHED_WAKE_IDLE
-#endif
-
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h
index 8a6d5d72bebbf..695690a5429bc 100644
--- a/include/asm-ia64/dma-mapping.h
+++ b/include/asm-ia64/dma-mapping.h
@@ -5,7 +5,8 @@
* Copyright (C) 2003-2004 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*/
-
+#include <linux/config.h>
+#include <linux/device.h>
#include <asm/machvec.h>
#define dma_alloc_coherent platform_dma_alloc_coherent
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 8433966536e62..a5c860fd69d80 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -520,7 +520,7 @@ do { \
# ifdef CONFIG_VIRTUAL_MEM_MAP
/* arch mem_map init routine is needed due to holes in a virtual mem_map */
# define __HAVE_ARCH_MEMMAP_INIT
- extern void memmap_init (struct page *start, unsigned long size, int nid, unsigned long zone,
+ extern void memmap_init (unsigned long size, int nid, unsigned long zone,
unsigned long start_pfn);
# endif /* CONFIG_VIRTUAL_MEM_MAP */
# endif /* !__ASSEMBLY__ */
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index f62f93c296a4f..6fa70c90c3992 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -334,6 +334,26 @@ struct task_struct;
/* Prepare to copy thread state - unlazy all lazy status */
#define prepare_to_copy(tsk) do { } while (0)
+#ifdef CONFIG_NUMA
+#define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .groups = NULL, \
+ .min_interval = 80, \
+ .max_interval = 320, \
+ .busy_factor = 320, \
+ .imbalance_pct = 125, \
+ .cache_hot_time = (10*1000000), \
+ .cache_nice_tries = 1, \
+ .per_cpu_gain = 100, \
+ .flags = SD_BALANCE_EXEC \
+ | SD_WAKE_BALANCE, \
+ .last_balance = jiffies, \
+ .balance_interval = 10, \
+ .nr_balance_failed = 0, \
+}
+#endif
+
/*
* This is the mechanism for creating a new kernel thread.
*
diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
index 61b6a191a2aeb..219af7fd06e4e 100644
--- a/include/asm-ppc/mpc8260.h
+++ b/include/asm-ppc/mpc8260.h
@@ -40,6 +40,10 @@
#include <platforms/pq2ads.h>
#endif
+#ifdef CONFIG_PCI_8260
+#include <syslib/m8260_pci.h>
+#endif
+
/* Make sure the memory translation stuff is there if PCI not used.
*/
#ifndef _IO_BASE
diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
index 38d8edb1ba706..8841a5cc21a9a 100644
--- a/include/asm-ppc/open_pic.h
+++ b/include/asm-ppc/open_pic.h
@@ -23,7 +23,7 @@
#define OPENPIC_VEC_TIMER 110 /* and up */
#define OPENPIC_VEC_IPI 118 /* and up */
-#define OPENPIC_VEC_SPURIOUS 127
+#define OPENPIC_VEC_SPURIOUS 239
/* OpenPIC IRQ controller structure */
extern struct hw_interrupt_type open_pic;
diff --git a/include/asm-ppc/residual.h b/include/asm-ppc/residual.h
index 42317589b538d..934810d256675 100644
--- a/include/asm-ppc/residual.h
+++ b/include/asm-ppc/residual.h
@@ -315,11 +315,20 @@ typedef struct _RESIDUAL {
} RESIDUAL;
+/*
+ * Forward declaration - we can't include <linux/pci.h> because it
+ * breaks the boot loader
+ */
+struct pci_dev;
+
extern RESIDUAL *res;
extern void print_residual_device_info(void);
extern PPC_DEVICE *residual_find_device(unsigned long BusMask,
unsigned char * DevID, int BaseType,
int SubType, int Interface, int n);
+extern int residual_pcidev_irq(struct pci_dev *dev);
+extern void residual_irq_mask(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern unsigned int residual_isapic_addr(void);
extern PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, unsigned packet_tag,
int n);
extern PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
@@ -328,6 +337,13 @@ extern PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
extern PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
unsigned packet_type,
int n);
+
+#ifdef CONFIG_PREP_RESIDUAL
+#define have_residual_data (res && res->ResidualLength)
+#else
+#define have_residual_data 0
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* ndef _RESIDUAL_ */
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
index 310206e286869..affec978627ef 100644
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -13,17 +13,17 @@
#elif defined(CONFIG_GEMINI)
#include <platforms/gemini_serial.h>
#elif defined(CONFIG_POWERPMC250)
-#include <platforms/powerpmc250_serial.h>
+#include <platforms/powerpmc250.h>
#elif defined(CONFIG_LOPEC)
-#include <platforms/lopec_serial.h>
+#include <platforms/lopec.h>
#elif defined(CONFIG_MCPN765)
-#include <platforms/mcpn765_serial.h>
+#include <platforms/mcpn765.h>
#elif defined(CONFIG_MVME5100)
-#include <platforms/mvme5100_serial.h>
+#include <platforms/mvme5100.h>
#elif defined(CONFIG_PRPMC750)
-#include <platforms/prpmc750_serial.h>
+#include <platforms/prpmc750.h>
#elif defined(CONFIG_PRPMC800)
-#include <platforms/prpmc800_serial.h>
+#include <platforms/prpmc800.h>
#elif defined(CONFIG_SANDPOINT)
#include <platforms/sandpoint.h>
#elif defined(CONFIG_SPRUCE)
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
index 13d3b96708f25..b8e80dfc96f30 100644
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -626,13 +626,10 @@ static inline void prefetchw(const void *x)
#define spin_lock_prefetch(x) prefetchw(x)
-#ifdef CONFIG_SCHED_SMT
-#define ARCH_HAS_SCHED_DOMAIN
-#define ARCH_HAS_SCHED_WAKE_IDLE
-#endif
-
#endif /* ASSEMBLY */
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
/*
* Number of entries in the SLB. If this ever changes we should handle
* it with a use a cpu feature fixup.
diff --git a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h
index 92195c568dbf9..40627b49f31c8 100644
--- a/include/asm-ppc64/smp.h
+++ b/include/asm-ppc64/smp.h
@@ -36,6 +36,8 @@ extern void smp_message_recv(int, struct pt_regs *);
#define smp_processor_id() (get_paca()->paca_index)
#define hard_smp_processor_id() (get_paca()->hw_cpu_id)
+extern cpumask_t cpu_sibling_map[NR_CPUS];
+
/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
*
* Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
index fb0b633e73aa2..dc3153fa414ec 100644
--- a/include/asm-ppc64/system.h
+++ b/include/asm-ppc64/system.h
@@ -105,6 +105,7 @@ extern int fix_alignment(struct pt_regs *regs);
extern void bad_page_fault(struct pt_regs *regs, unsigned long address,
int sig);
extern void show_regs(struct pt_regs * regs);
+extern void low_hash_fault(struct pt_regs *regs, unsigned long address);
extern int die(const char *str, struct pt_regs *regs, long err);
extern void flush_instruction_cache(void);
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index 4c9d607021d7f..b99592e37d3b1 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -76,6 +76,8 @@ extern struct task_struct *last_task_used_math;
#define MM_VM_SIZE(mm) DEFAULT_TASK_SIZE
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
typedef struct {
__u32 ar4;
} mm_segment_t;
diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h
index bb49c6999055e..454d1ea85c547 100644
--- a/include/asm-s390/timer.h
+++ b/include/asm-s390/timer.h
@@ -45,6 +45,4 @@ extern void add_virt_timer_periodic(void *new);
extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires);
extern int del_virt_timer(struct vtimer_list *timer);
-int stop_timers(void);
-
#endif
diff --git a/include/asm-sparc/sigcontext.h b/include/asm-sparc/sigcontext.h
index ff9ccda164ce5..86dc000ad681d 100644
--- a/include/asm-sparc/sigcontext.h
+++ b/include/asm-sparc/sigcontext.h
@@ -57,20 +57,6 @@ typedef struct {
} si_fpqueue [16];
} __siginfo_fpu_t;
-#ifdef __KERNEL__
-
-/* This magic should be in g_upper[0] for all upper parts
- to be valid.
- This is generated by sparc64 only, but for 32bit processes,
- so we define it here as well. */
-#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
-typedef struct {
- unsigned int g_upper[8];
- unsigned int o_upper[8];
-} siginfo_extra_v8plus_t;
-
-#endif
-
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC_SIGCONTEXT_H) */
diff --git a/include/asm-sparc64/sigcontext.h b/include/asm-sparc64/sigcontext.h
index d7128a8757bfb..d8073373db8cb 100644
--- a/include/asm-sparc64/sigcontext.h
+++ b/include/asm-sparc64/sigcontext.h
@@ -83,18 +83,6 @@ struct sigcontext {
unsigned long sigc_mask;
};
-#ifdef __KERNEL__
-
-/* This magic should be in g_upper[0] for all upper parts
- to be valid. */
-#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
-typedef struct {
- unsigned int g_upper[8];
- unsigned int o_upper[8];
-} siginfo_extra_v8plus_t;
-
-#endif
-
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC64_SIGCONTEXT_H) */
diff --git a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h
index a23261baab5db..85fd033585211 100644
--- a/include/asm-um/archparam-i386.h
+++ b/include/asm-um/archparam-i386.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -56,6 +56,93 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
pr_reg[16] = PT_REGS_SS(regs); \
} while(0);
+#if 0 /* Turn this back on when UML has VSYSCALL working */
+#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL))
+#else
+#define VSYSCALL_BASE 0
+#endif
+
+#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE)
+#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall)
+extern void *__kernel_vsyscall;
+
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them, start the x86-specific ones at 32.
+ */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+#define ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \
+} while (0)
+
+/*
+ * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
+ * extra segments containing the vsyscall DSO contents. Dumping its
+ * contents makes post-mortem fully interpretable later without matching up
+ * the same kernel and hardware config to see what PC values meant.
+ * Dumping its extra ELF program headers includes all the other information
+ * a debugger needs to easily find how the vsyscall DSO was being used.
+ */
+#if 0
+#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum)
+#endif
+
+#undef ELF_CORE_EXTRA_PHDRS
+
+#if 0
+#define ELF_CORE_WRITE_EXTRA_PHDRS \
+do { \
+ const struct elf_phdr *const vsyscall_phdrs = \
+ (const struct elf_phdr *) (VSYSCALL_BASE \
+ + VSYSCALL_EHDR->e_phoff); \
+ int i; \
+ Elf32_Off ofs = 0; \
+ for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \
+ struct elf_phdr phdr = vsyscall_phdrs[i]; \
+ if (phdr.p_type == PT_LOAD) { \
+ ofs = phdr.p_offset = offset; \
+ offset += phdr.p_filesz; \
+ } \
+ else \
+ phdr.p_offset += ofs; \
+ phdr.p_paddr = 0; /* match other core phdrs */ \
+ DUMP_WRITE(&phdr, sizeof(phdr)); \
+ } \
+} while (0)
+#define ELF_CORE_WRITE_EXTRA_DATA \
+do { \
+ const struct elf_phdr *const vsyscall_phdrs = \
+ (const struct elf_phdr *) (VSYSCALL_BASE \
+ + VSYSCALL_EHDR->e_phoff); \
+ int i; \
+ for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \
+ if (vsyscall_phdrs[i].p_type == PT_LOAD) \
+ DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \
+ vsyscall_phdrs[i].p_filesz); \
+ } \
+} while (0)
+#endif
+
+#undef ELF_CORE_WRITE_EXTRA_PHDRS
+#undef ELF_CORE_WRITE_EXTRA_DATA
+
+#define R_386_NONE 0
+#define R_386_32 1
+#define R_386_PC32 2
+#define R_386_GOT32 3
+#define R_386_PLT32 4
+#define R_386_COPY 5
+#define R_386_GLOB_DAT 6
+#define R_386_JMP_SLOT 7
+#define R_386_RELATIVE 8
+#define R_386_GOTOFF 9
+#define R_386_GOTPC 10
+#define R_386_NUM 11
+
/********* Bits for asm-um/delay.h **********/
typedef unsigned long um_udelay_t;
diff --git a/include/asm-um/common.lds.S b/include/asm-um/common.lds.S
index d2517a04c54f8..a3d6aab0e74dc 100644
--- a/include/asm-um/common.lds.S
+++ b/include/asm-um/common.lds.S
@@ -1,3 +1,5 @@
+#include <asm-generic/vmlinux.lds.h>
+
.fini : { *(.fini) } =0x9090
_etext = .;
PROVIDE (etext = .);
@@ -13,18 +15,6 @@
RODATA
- __start___ksymtab = .; /* Kernel symbol table */
- __ksymtab : { *(__ksymtab) }
- __stop___ksymtab = .;
-
- __start___gpl_ksymtab = .; /* Kernel symbol table: GPL-only symbols */
- __gpl_ksymtab : { *(__gpl_ksymtab) }
- __stop___gpl_ksymtab = .;
-
- __start___kallsyms = .; /* All kernel symbols */
- __kallsyms : { *(__kallsyms) }
- __stop___kallsyms = .;
-
.unprotected : { *(.unprotected) }
. = ALIGN(4096);
PROVIDE (_unprotected_end = .);
@@ -46,10 +36,6 @@
.init.setup : { *(.init.setup) }
__setup_end = .;
- __start___param = .;
- __param : { *(__param) }
- __stop___param = .;
-
. = ALIGN(32);
__per_cpu_start = . ;
.data.percpu : { *(.data.percpu) }
@@ -67,11 +53,17 @@
}
__initcall_end = .;
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
+
__uml_initcall_start = .;
.uml.initcall.init : { *(.uml.initcall.init) }
__uml_initcall_end = .;
__init_end = .;
+ SECURITY_INIT
+
__exitcall_begin = .;
.exitcall : { *(.exitcall.exit) }
__exitcall_end = .;
@@ -80,7 +72,33 @@
.uml.exitcall : { *(.uml.exitcall.exit) }
__uml_exitcall_end = .;
- . = ALIGN(4096);
+ . = ALIGN(4);
+ __alt_instructions = .;
+ .altinstructions : { *(.altinstructions) }
+ __alt_instructions_end = .;
+ .altinstr_replacement : { *(.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) }
+
+ __preinit_array_start = .;
+ .preinit_array : { *(.preinit_array) }
+ __preinit_array_end = .;
+ __init_array_start = .;
+ .init_array : { *(.init_array) }
+ __init_array_end = .;
+ __fini_array_start = .;
+ .fini_array : { *(.fini_array) }
+ __fini_array_end = .;
+
+ . = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ *(.exitcall.exit)
+ }
+
diff --git a/include/asm-um/cpufeature.h b/include/asm-um/cpufeature.h
new file mode 100644
index 0000000000000..fb7bd42a4d968
--- /dev/null
+++ b/include/asm-um/cpufeature.h
@@ -0,0 +1,6 @@
+#ifndef __UM_CPUFEATURE_H
+#define __UM_CPUFEATURE_H
+
+#include "asm/arch/cpufeature.h"
+
+#endif
diff --git a/include/asm-um/current.h b/include/asm-um/current.h
index adfe568cfcd1b..72a4cbd91483c 100644
--- a/include/asm-um/current.h
+++ b/include/asm-um/current.h
@@ -16,8 +16,10 @@ struct thread_info;
#define CURRENT_THREAD(dummy) (((unsigned long) &dummy) & \
(PAGE_MASK << CONFIG_KERNEL_STACK_ORDER))
-#define current ({ int dummy; \
- ((struct thread_info *) CURRENT_THREAD(dummy))->task; })
+#define current_thread \
+ ({ int dummy; ((struct thread_info *) CURRENT_THREAD(dummy)); })
+
+#define current (current_thread->task)
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-um/dma-mapping.h b/include/asm-um/dma-mapping.h
index e7e16901f686b..2ea88281161d0 100644
--- a/include/asm-um/dma-mapping.h
+++ b/include/asm-um/dma-mapping.h
@@ -1 +1,119 @@
-#include <asm-generic/dma-mapping.h>
+#ifndef _ASM_DMA_MAPPING_H
+#define _ASM_DMA_MAPPING_H
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+ BUG();
+ return(0);
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+ BUG();
+ return(0);
+}
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ int flag)
+{
+ BUG();
+ return((void *) 0);
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t dma_handle)
+{
+ BUG();
+}
+
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+ return(0);
+}
+
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+ return(0);
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ BUG();
+ return(0);
+}
+
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+static inline void
+dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+static inline void
+dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d) (1)
+
+static inline int
+dma_get_cache_alignment(void)
+{
+ BUG();
+ return(0);
+}
+
+static inline void
+dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+static inline void
+dma_cache_sync(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG();
+}
+
+#endif
diff --git a/include/asm-um/elf.h b/include/asm-um/elf.h
index f33a3533fef7a..c96c5eb923096 100644
--- a/include/asm-um/elf.h
+++ b/include/asm-um/elf.h
@@ -15,4 +15,17 @@
#define USE_ELF_CORE_DUMP
+#define R_386_NONE 0
+#define R_386_32 1
+#define R_386_PC32 2
+#define R_386_GOT32 3
+#define R_386_PLT32 4
+#define R_386_COPY 5
+#define R_386_GLOB_DAT 6
+#define R_386_JMP_SLOT 7
+#define R_386_RELATIVE 8
+#define R_386_GOTOFF 9
+#define R_386_GOTPC 10
+#define R_386_NUM 11
+
#endif
diff --git a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h
index 0e8a4c1ace9c4..ef4890b11982a 100644
--- a/include/asm-um/fixmap.h
+++ b/include/asm-um/fixmap.h
@@ -34,6 +34,7 @@ enum fixed_addresses {
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
+ FIX_VSYSCALL,
__end_of_fixed_addresses
};
@@ -63,6 +64,13 @@ extern unsigned long get_kmem_end(void);
#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+/*
+ * This is the range that is readable by user mode, and things
+ * acting like user mode such as get_user_pages.
+ */
+#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL))
+#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
+
extern void __this_fixmap_does_not_exist(void);
/*
diff --git a/include/asm-um/irq.h b/include/asm-um/irq.h
index 8300c209a1bc0..de389a477cdd6 100644
--- a/include/asm-um/irq.h
+++ b/include/asm-um/irq.h
@@ -1,15 +1,6 @@
#ifndef __UM_IRQ_H
#define __UM_IRQ_H
-/* The i386 irq.h has a struct task_struct in a prototype without including
- * sched.h. This forward declaration kills the resulting warning.
- */
-struct task_struct;
-
-#include "asm/ptrace.h"
-
-#undef NR_IRQS
-
#define TIMER_IRQ 0
#define UMN_IRQ 1
#define CONSOLE_IRQ 2
@@ -28,13 +19,4 @@ struct task_struct;
#define LAST_IRQ XTERM_IRQ
#define NR_IRQS (LAST_IRQ + 1)
-extern int um_request_irq(unsigned int irq, int fd, int type,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname,
- void *dev_id);
-
-struct irqaction;
-struct pt_regs;
-int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
-
#endif
diff --git a/include/asm-um/local.h b/include/asm-um/local.h
new file mode 100644
index 0000000000000..9a280c5bb609c
--- /dev/null
+++ b/include/asm-um/local.h
@@ -0,0 +1,6 @@
+#ifndef __UM_LOCAL_H
+#define __UM_LOCAL_H
+
+#include "asm/arch/local.h"
+
+#endif
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 4ddffc1a78325..89bff310b7a90 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -26,8 +26,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
unsigned cpu = smp_processor_id();
if(prev != next){
- clear_bit(cpu, &prev->cpu_vm_mask);
- set_bit(cpu, &next->cpu_vm_mask);
+ cpu_clear(cpu, prev->cpu_vm_mask);
+ cpu_set(cpu, next->cpu_vm_mask);
if(next != &init_mm)
CHOOSE_MODE((void) 0,
switch_mm_skas(next->context.skas.mm_fd));
diff --git a/include/asm-um/module-generic.h b/include/asm-um/module-generic.h
new file mode 100644
index 0000000000000..5a265f56b1740
--- /dev/null
+++ b/include/asm-um/module-generic.h
@@ -0,0 +1,6 @@
+#ifndef __UM_MODULE_GENERIC_H
+#define __UM_MODULE_GENERIC_H
+
+#include "asm/arch/module.h"
+
+#endif
diff --git a/include/asm-um/module.h b/include/asm-um/module-i386.h
index dae3ddf6b5d02..5ead4a0b2e352 100644
--- a/include/asm-um/module.h
+++ b/include/asm-um/module-i386.h
@@ -1,5 +1,5 @@
-#ifndef __UM_MODULE_H
-#define __UM_MODULE_H
+#ifndef __UM_MODULE_I386_H
+#define __UM_MODULE_I386_H
/* UML is simple */
struct mod_arch_specific
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index ad97bc0a61353..f69b0f1c270ed 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -1,10 +1,14 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_PAGE_H
#define __UM_PAGE_H
struct page;
#include "asm/arch/page.h"
-#include "asm/bug.h"
#undef __pa
#undef __va
@@ -24,25 +28,25 @@ extern unsigned long uml_physmem;
#define __va_space (8*1024*1024)
-extern unsigned long region_pa(void *virt);
-extern void *region_va(unsigned long phys);
-
-#define __pa(virt) region_pa((void *) (virt))
-#define __va(phys) region_va((unsigned long) (phys))
-
-extern unsigned long page_to_pfn(struct page *page);
-extern struct page *pfn_to_page(unsigned long pfn);
+extern unsigned long to_phys(void *virt);
+extern void *to_virt(unsigned long phys);
-extern struct page *phys_to_page(unsigned long phys);
+#define __pa(virt) to_phys((void *) virt)
+#define __va(phys) to_virt((unsigned long) phys)
-#define virt_to_page(v) (phys_to_page(__pa(v)))
+#define page_to_pfn(page) ((page) - mem_map)
+#define pfn_to_page(pfn) (mem_map + (pfn))
-extern struct page *page_mem_map(struct page *page);
-
-#define pfn_valid(pfn) (page_mem_map(pfn_to_page(pfn)) != NULL)
-#define virt_addr_valid(v) pfn_valid(__pa(v) >> PAGE_SHIFT)
+#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
+#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT)
+#define pfn_valid(pfn) ((pfn) < max_mapnr)
+#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
+
extern struct page *arch_validate(struct page *page, int mask, int order);
#define HAVE_ARCH_VALIDATE
+extern void arch_free_page(struct page *page, int order);
+#define HAVE_ARCH_FREE_PAGE
+
#endif
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 148dd8e4200b9..d013cc3763cb0 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -12,8 +12,6 @@
#include "asm/page.h"
#include "asm/fixmap.h"
-extern pgd_t swapper_pg_dir[1024];
-
extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
pte_t *pte_out);
@@ -49,6 +47,8 @@ extern unsigned long *empty_zero_page;
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
/*
* pgd entries used up by user/kernel:
*/
@@ -65,10 +65,10 @@ extern unsigned long *empty_zero_page;
* area for the same reason. ;)
*/
-extern unsigned long high_physmem;
+extern unsigned long end_iomem;
#define VMALLOC_OFFSET (__va_space)
-#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
@@ -78,12 +78,13 @@ extern unsigned long high_physmem;
#define _PAGE_PRESENT 0x001
#define _PAGE_NEWPAGE 0x002
-#define _PAGE_PROTNONE 0x004 /* If not present */
-#define _PAGE_RW 0x008
-#define _PAGE_USER 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_NEWPROT 0x080
+#define _PAGE_NEWPROT 0x004
+#define _PAGE_FILE 0x008 /* set:pagecache unset:swap */
+#define _PAGE_PROTNONE 0x010 /* If not present */
+#define _PAGE_RW 0x020
+#define _PAGE_USER 0x040
+#define _PAGE_ACCESSED 0x080
+#define _PAGE_DIRTY 0x100
#define REGION_MASK 0xf0000000
#define REGION_SHIFT 28
@@ -143,7 +144,8 @@ extern pte_t * __bad_pagetable(void);
#define BAD_PAGETABLE __bad_pagetable()
#define BAD_PAGE __bad_page()
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
/* number of bits that fit into a memory pointer */
#define BITS_PER_PTR (8*sizeof(unsigned long))
@@ -164,9 +166,6 @@ extern pte_t * __bad_pagetable(void);
#define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
-#define phys_region_index(x) (((x) & REGION_MASK) >> REGION_SHIFT)
-#define pte_region_index(x) phys_region_index(pte_val(x))
-
#define pmd_none(x) (!(pmd_val(x) & ~_PAGE_NEWPAGE))
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
@@ -188,19 +187,25 @@ static inline void pgd_clear(pgd_t * pgdp) { }
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-extern struct page *pte_mem_map(pte_t pte);
-extern struct page *phys_mem_map(unsigned long phys);
-extern unsigned long phys_to_pfn(unsigned long p);
-extern unsigned long pfn_to_phys(unsigned long pfn);
+#define pte_page(pte) phys_to_page(pte_val(pte))
+#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
-#define pte_page(x) pfn_to_page(pte_pfn(x))
-#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
-#define mk_phys(a, r) ((a) + (r << REGION_SHIFT))
-#define phys_addr(p) ((p) & ~REGION_MASK)
-#define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT))
#define pte_pfn(x) phys_to_pfn(pte_val(x))
#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
-#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
+
+extern struct page *phys_to_page(const unsigned long phys);
+extern struct page *__virt_to_page(const unsigned long virt);
+#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
+
+/*
+ * Bits 0 through 3 are taken
+ */
+#define PTE_FILE_MAX_BITS 28
+
+#define pte_to_pgoff(pte) ((pte).pte_low >> 4)
+
+#define pgoff_to_pte(off) \
+ ((pte_t) { ((off) << 4) + _PAGE_FILE })
static inline pte_t pte_mknewprot(pte_t pte)
{
@@ -235,6 +240,12 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
+static inline int pte_user(pte_t pte)
+{
+ return((pte_val(pte) & _PAGE_USER) &&
+ !(pte_val(pte) & _PAGE_PROTNONE));
+}
+
static inline int pte_read(pte_t pte)
{
return((pte_val(pte) & _PAGE_USER) &&
@@ -252,6 +263,14 @@ static inline int pte_write(pte_t pte)
!(pte_val(pte) & _PAGE_PROTNONE));
}
+/*
+ * The following only works if pte_present() is not true.
+ */
+static inline int pte_file(pte_t pte)
+{
+ return (pte).pte_low & _PAGE_FILE;
+}
+
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
@@ -334,14 +353,7 @@ extern unsigned long page_to_phys(struct page *page);
* and a page entry and page directory to the page they refer to.
*/
-#define mk_pte(page, pgprot) \
-({ \
- pte_t __pte; \
- \
- pte_val(__pte) = page_to_phys(page) + pgprot_val(pgprot);\
- if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \
- __pte; \
-})
+extern pte_t mk_pte(struct page *page, pgprot_t pgprot);
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
@@ -351,17 +363,27 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
}
#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-#define pmd_page(pmd) (phys_mem_map(pmd_val(pmd) & PAGE_MASK) + \
- ((phys_addr(pmd_val(pmd)) >> PAGE_SHIFT)))
-/* to find an entry in a page-table-directory. */
+/*
+ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
+ *
+ * this macro returns the index of the entry in the pgd page which would
+ * control the given virtual address
+ */
#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-/* to find an entry in a page-table-directory */
+/*
+ * pgd_offset() returns a (pgd_t *)
+ * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
+ */
#define pgd_offset(mm, address) \
((mm)->pgd + ((address) >> PGDIR_SHIFT))
-/* to find an entry in a kernel page-table-directory */
+
+/*
+ * a shortcut which implies the use of the kernel's pgd, instead
+ * of a process's
+ */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
#define pmd_index(address) \
@@ -373,7 +395,12 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
return (pmd_t *) dir;
}
-/* Find an entry in the third-level page table.. */
+/*
+ * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
+ *
+ * this macro returns the index of the entry in the pte page which would
+ * control the given virtual address
+ */
#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address))
@@ -387,11 +414,11 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
#define update_mmu_cache(vma,address,pte) do ; while (0)
/* Encode and de-code a swap entry */
-#define __swp_type(x) (((x).val >> 3) & 0x7f)
-#define __swp_offset(x) ((x).val >> 10)
+#define __swp_type(x) (((x).val >> 4) & 0x3f)
+#define __swp_offset(x) ((x).val >> 11)
#define __swp_entry(type, offset) \
- ((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
+ ((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
#define __pte_to_swp_entry(pte) \
((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
index 618a490309427..d8f6db8e83d5e 100644
--- a/include/asm-um/processor-generic.h
+++ b/include/asm-um/processor-generic.h
@@ -11,33 +11,14 @@ struct pt_regs;
struct task_struct;
#include "linux/config.h"
-#include "linux/signal.h"
#include "asm/ptrace.h"
-#include "asm/siginfo.h"
#include "choose-mode.h"
struct mm_struct;
#define current_text_addr() ((void *) 0)
-#define cpu_relax() do ; while (0)
-
-#ifdef CONFIG_MODE_TT
-struct proc_tt_mode {
- int extern_pid;
- int tracing;
- int switch_pipe[2];
- int singlestep_syscall;
- int vm_seq;
-};
-#endif
-
-#ifdef CONFIG_MODE_SKAS
-struct proc_skas_mode {
- void *switch_buf;
- void *fork_buf;
-};
-#endif
+#define cpu_relax() barrier()
struct thread_struct {
int forking;
@@ -46,6 +27,7 @@ struct thread_struct {
struct pt_regs regs;
unsigned long cr2;
int err;
+ unsigned long trap_no;
void *fault_addr;
void *fault_catcher;
struct task_struct *prev_sched;
@@ -54,10 +36,20 @@ struct thread_struct {
struct arch_thread arch;
union {
#ifdef CONFIG_MODE_TT
- struct proc_tt_mode tt;
+ struct {
+ int extern_pid;
+ int tracing;
+ int switch_pipe[2];
+ int singlestep_syscall;
+ int vm_seq;
+ } tt;
#endif
#ifdef CONFIG_MODE_SKAS
- struct proc_skas_mode skas;
+ struct {
+ void *switch_buf;
+ void *fork_buf;
+ int mm_count;
+ } skas;
#endif
} mode;
struct {
@@ -99,14 +91,19 @@ typedef struct {
} mm_segment_t;
extern struct task_struct *alloc_task_struct(void);
-extern void free_task_struct(struct task_struct *task);
extern void release_thread(struct task_struct *);
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern void dump_thread(struct pt_regs *regs, struct user *u);
+extern void prepare_to_copy(struct task_struct *tsk);
extern unsigned long thread_saved_pc(struct task_struct *t);
+static inline void mm_copy_segments(struct mm_struct *from_mm,
+ struct mm_struct *new_mm)
+{
+}
+
#define init_stack (init_thread_union.stack)
/*
diff --git a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
index 02decdcc103f8..0f08c0225029c 100644
--- a/include/asm-um/processor-i386.h
+++ b/include/asm-um/processor-i386.h
@@ -6,8 +6,8 @@
#ifndef __UM_PROCESSOR_I386_H
#define __UM_PROCESSOR_I386_H
-extern int cpu_has_xmm;
-extern int cpu_has_cmov;
+extern int host_has_xmm;
+extern int host_has_cmov;
struct arch_thread {
unsigned long debugregs[8];
diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
index c5a13e609b1d4..8c472ebbb540c 100644
--- a/include/asm-um/ptrace-generic.h
+++ b/include/asm-um/ptrace-generic.h
@@ -45,6 +45,8 @@ struct pt_regs {
#define PT_REGS_SC(r) UPT_SC(&(r)->regs)
+#define instruction_pointer(regs) PT_REGS_IP(regs)
+
struct task_struct;
extern unsigned long getreg(struct task_struct *child, int regno);
diff --git a/include/asm-um/sections.h b/include/asm-um/sections.h
new file mode 100644
index 0000000000000..6b0231eefea8f
--- /dev/null
+++ b/include/asm-um/sections.h
@@ -0,0 +1,7 @@
+#ifndef _UM_SECTIONS_H
+#define _UM_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+#endif
diff --git a/include/asm-um/smp.h b/include/asm-um/smp.h
index 4629de8666a45..20c6457f30381 100644
--- a/include/asm-um/smp.h
+++ b/include/asm-um/smp.h
@@ -10,7 +10,7 @@
extern cpumask_t cpu_online_map;
-#define smp_processor_id() (current->thread_info->cpu)
+#define smp_processor_id() (current_thread->cpu)
#define cpu_logical_map(n) (n)
#define cpu_number_map(n) (n)
#define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */
diff --git a/include/asm-um/smplock.h b/include/asm-um/smplock.h
deleted file mode 100644
index aacda39c51918..0000000000000
--- a/include/asm-um/smplock.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __UM_SMPLOCK_H
-#define __UM_SMPLOCK_H
-
-#include "asm/arch/smplock.h"
-
-#endif
diff --git a/include/asm-um/spinlock.h b/include/asm-um/spinlock.h
deleted file mode 100644
index bd6c35d4874ca..0000000000000
--- a/include/asm-um/spinlock.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __UM_SPINLOCK_H
-#define __UM_SPINLOCK_H
-
-#include "linux/config.h"
-
-#ifdef CONFIG_SMP
-#include "asm/arch/spinlock.h"
-#endif
-
-#endif
diff --git a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h
index 80b24a31b5fe3..5bcfa35e7a22c 100644
--- a/include/asm-um/system-generic.h
+++ b/include/asm-um/system-generic.h
@@ -23,8 +23,10 @@ extern int get_signals(void);
extern void block_signals(void);
extern void unblock_signals(void);
-#define local_save_flags(flags) do { (flags) = get_signals(); } while(0)
-#define local_irq_restore(flags) do { set_signals(flags); } while(0)
+#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
+ (flags) = get_signals(); } while(0)
+#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \
+ set_signals(flags); } while(0)
#define local_irq_save(flags) do { local_save_flags(flags); \
local_irq_disable(); } while(0)
@@ -39,4 +41,7 @@ extern void unblock_signals(void);
(flags == 0); \
})
+extern void *_switch_to(void *prev, void *next, void *last);
+#define switch_to(prev, next, last) prev = _switch_to(prev, next, last)
+
#endif
diff --git a/include/asm-um/system-i386.h b/include/asm-um/system-i386.h
index 4d71ed390d02d..c436263e67ba1 100644
--- a/include/asm-um/system-i386.h
+++ b/include/asm-um/system-i386.h
@@ -2,36 +2,5 @@
#define __UM_SYSTEM_I386_H
#include "asm/system-generic.h"
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
-#define cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
#endif
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 6a606bf0b6847..c52830772a335 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -9,6 +9,7 @@
#ifndef __ASSEMBLY__
#include <asm/processor.h>
+#include <asm/types.h>
struct thread_info {
struct task_struct *task; /* main task structure */
@@ -43,15 +44,18 @@ struct thread_info {
static inline struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
- __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~16383UL));
+ unsigned long mask = PAGE_SIZE *
+ (1 << CONFIG_KERNEL_STACK_ORDER) - 1;
+ __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~mask));
return ti;
}
/* thread information allocation */
-#define THREAD_SIZE (4*PAGE_SIZE)
-#define alloc_thread_info(tsk) ((struct thread_info *) \
- __get_free_pages(GFP_KERNEL,2))
-#define free_thread_info(ti) free_pages((unsigned long) (ti), 2)
+#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
+#define alloc_thread_info(tsk) \
+ ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL))
+#define free_thread_info(ti) kfree(ti)
+
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
@@ -65,11 +69,13 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling
* TIF_NEED_RESCHED
*/
+#define TIF_RESTART_BLOCK 4
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+#define _TIF_RESTART_BLOCK (1 << TIF_RESTART_BLOCK)
#endif
diff --git a/include/asm-um/timex.h b/include/asm-um/timex.h
index 6a873133ac01e..580581172e978 100644
--- a/include/asm-um/timex.h
+++ b/include/asm-um/timex.h
@@ -1,8 +1,6 @@
#ifndef __UM_TIMEX_H
#define __UM_TIMEX_H
-#include "linux/time.h"
-
typedef unsigned long cycles_t;
#define cacheflush_time (0)
diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h
index e1dfea1088579..02e918824e98f 100644
--- a/include/asm-um/uaccess.h
+++ b/include/asm-um/uaccess.h
@@ -6,6 +6,8 @@
#ifndef __UM_UACCESS_H
#define __UM_UACCESS_H
+#include "linux/sched.h"
+
#define VERIFY_READ 0
#define VERIFY_WRITE 1
diff --git a/include/asm-um/unistd.h b/include/asm-um/unistd.h
index 5850620bb3385..512f2257cff52 100644
--- a/include/asm-um/unistd.h
+++ b/include/asm-um/unistd.h
@@ -48,7 +48,10 @@ extern int um_execve(const char *file, char *const argv[], char *const env[]);
set_fs(KERNEL_DS); \
ret = sys(args); \
set_fs(fs); \
- return ret;
+ if (ret >= 0) \
+ return ret; \
+ errno = -(long)ret; \
+ return -1;
static inline long open(const char *pathname, int flags, int mode)
{
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index 69876114f66b8..015faa095c2b1 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -99,6 +99,11 @@ __acpi_release_global_lock (unsigned int *lock)
:"=r"(n_hi), "=r"(n_lo) \
:"0"(n_hi), "1"(n_lo))
+/*
+ * Refer Intel ACPI _PDC support document for bit definitions
+ */
+#define ACPI_PDC_EST_CAPABILITY_SMP 0xa
+#define ACPI_PDC_EST_CAPABILITY_MSR 0x1
#ifdef CONFIG_ACPI_BOOT
extern int acpi_lapic;
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index c91f028db682e..c44e168f13d19 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -25,10 +25,10 @@
* Note that @nr may be almost arbitrarily large; this function is not
* restricted to acting on a single-word quantity.
*/
-static __inline__ void set_bit(long nr, volatile void * addr)
+static __inline__ void set_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
- "btsq %1,%0"
+ "btsl %1,%0"
:"=m" (ADDR)
:"dIr" (nr) : "memory");
}
@@ -254,128 +254,37 @@ static __inline__ int variable_test_bit(int nr, volatile const void * addr)
#undef ADDR
-/**
- * find_first_zero_bit - find the first zero bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first zero bit, not the number of the byte
- * containing a bit.
- */
-static __inline__ int find_first_zero_bit(const unsigned long * addr, unsigned size)
-{
- int d0, d1, d2;
- int res;
-
- if (!size)
- return 0;
- __asm__ __volatile__(
- "movl $-1,%%eax\n\t"
- "xorl %%edx,%%edx\n\t"
- "repe; scasl\n\t"
- "je 1f\n\t"
- "xorl -4(%%rdi),%%eax\n\t"
- "subq $4,%%rdi\n\t"
- "bsfl %%eax,%%edx\n"
- "1:\tsubq %%rbx,%%rdi\n\t"
- "shlq $3,%%rdi\n\t"
- "addq %%rdi,%%rdx"
- :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
- :"1" ((size + 31) >> 5), "2" (addr), "b" (addr) : "memory");
- return res;
-}
+extern long find_first_zero_bit(const unsigned long * addr, unsigned long size);
+extern long find_next_zero_bit (const unsigned long * addr, long size, long offset);
+extern long find_first_bit(const unsigned long * addr, unsigned long size);
+extern long find_next_bit(const unsigned long * addr, long size, long offset);
-/**
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static __inline__ int find_next_zero_bit (const unsigned long * addr, int size, int offset)
+/* return index of first bet set in val or max when no bit is set */
+static inline unsigned long __scanbit(unsigned long val, unsigned long max)
{
- unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
- unsigned long set = 0;
- unsigned long res, bit = offset&63;
-
- if (bit) {
- /*
- * Look for zero in first word
- */
- __asm__("bsfq %1,%0\n\t"
- "cmoveq %2,%0"
- : "=r" (set)
- : "r" (~(*p >> bit)), "r"(64L));
- if (set < (64 - bit))
- return set + offset;
- set = 64 - bit;
- p++;
- }
- /*
- * No zero yet, search remaining full words for a zero
- */
- res = find_first_zero_bit ((const unsigned long *)p, size - 64 * (p - (unsigned long *) addr));
- return (offset + set + res);
+ asm("bsfq %1,%0 ; cmovz %2,%0" : "=&r" (val) : "r" (val), "r" (max));
+ return val;
}
+#define find_first_bit(addr,size) \
+((__builtin_constant_p(size) && size <= BITS_PER_LONG ? \
+ (__scanbit(*(unsigned long *)addr,(size))) : \
+ find_first_bit(addr,size)))
-/**
- * find_first_bit - find the first set bit in a memory region
- * @addr: The address to start the search at
- * @size: The maximum size to search
- *
- * Returns the bit-number of the first set bit, not the number of the byte
- * containing a bit.
- */
-static __inline__ int find_first_bit(const unsigned long * addr, unsigned size)
-{
- int d0, d1;
- int res;
-
- /* This looks at memory. Mark it volatile to tell gcc not to move it around */
- __asm__ __volatile__(
- "xorl %%eax,%%eax\n\t"
- "repe; scasl\n\t"
- "jz 1f\n\t"
- "leaq -4(%%rdi),%%rdi\n\t"
- "bsfl (%%rdi),%%eax\n"
- "1:\tsubq %%rbx,%%rdi\n\t"
- "shll $3,%%edi\n\t"
- "addl %%edi,%%eax"
- :"=a" (res), "=&c" (d0), "=&D" (d1)
- :"1" ((size + 31) >> 5), "2" (addr), "b" (addr) : "memory");
- return res;
-}
+#define find_next_bit(addr,size,off) \
+((__builtin_constant_p(size) && size <= BITS_PER_LONG ? \
+ ((off) + (__scanbit((*(unsigned long *)addr) >> (off),(size)-(off)))) : \
+ find_next_bit(addr,size,off)))
-/**
- * find_next_bit - find the first set bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static __inline__ int find_next_bit(const unsigned long * addr, int size, int offset)
-{
- const unsigned long * p = addr + (offset >> 6);
- unsigned long set = 0, bit = offset & 63, res;
+#define find_first_zero_bit(addr,size) \
+((__builtin_constant_p(size) && size <= BITS_PER_LONG ? \
+ (__scanbit(~*(unsigned long *)addr,(size))) : \
+ find_first_zero_bit(addr,size)))
- if (bit) {
- /*
- * Look for nonzero in the first 64 bits:
- */
- __asm__("bsfq %1,%0\n\t"
- "cmoveq %2,%0\n\t"
- : "=r" (set)
- : "r" (*p >> bit), "r" (64L));
- if (set < (64 - bit))
- return set + offset;
- set = 64 - bit;
- p++;
- }
- /*
- * No set bit yet, search remaining full words for a bit
- */
- res = find_first_bit (p, size - 64 * (p - addr));
- return (offset + set + res);
-}
+#define find_next_zero_bit(addr,size,off) \
+((__builtin_constant_p(size) && size <= BITS_PER_LONG ? \
+ ((off)+(__scanbit(~(((*(unsigned long *)addr)) >> (off)),(size)-(off)))) : \
+ find_next_zero_bit(addr,size,off)))
/*
* Find string of zero bits in a bitmap. -1 when not found.
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
index d82d84032838f..71a401fa3fa55 100644
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -63,8 +63,14 @@
#define X86_FEATURE_K8_C (3*32+ 4) /* C stepping K8 */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
+#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */
+#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_CID (4*32+10) /* Context ID */
+#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */
+#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */
#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
#define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability)
@@ -81,6 +87,8 @@
#define cpu_has_mmx 1
#define cpu_has_fxsr 1
#define cpu_has_xmm 1
+#define cpu_has_xmm2 1
+#define cpu_has_xmm3 boot_cpu_has(X86_FEATURE_XMM3)
#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT)
#define cpu_has_mp 1 /* XXX */
#define cpu_has_k6_mtrr 0
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index 414efa3c3bcbc..95102ecc1b706 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -1,6 +1,139 @@
#ifndef _X8664_DMA_MAPPING_H
#define _X8664_DMA_MAPPING_H 1
-#include <asm-generic/dma-mapping.h>
+/*
+ * IOMMU interface. See Documentation/DMA-mapping.txt and DMA-API.txt for
+ * documentation.
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+#include <asm/swiotlb.h>
+
+extern dma_addr_t bad_dma_address;
+#define dma_mapping_error(x) \
+ (swiotlb ? swiotlb_dma_mapping_error(x) : ((x) == bad_dma_address))
+
+void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ unsigned gfp);
+void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle);
+
+#ifdef CONFIG_GART_IOMMU
+
+extern dma_addr_t dma_map_single(struct device *hwdev, void *ptr, size_t size,
+ int direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
+ int direction);
+
+#else
+
+/* No IOMMU */
+
+static inline dma_addr_t dma_map_single(struct device *hwdev, void *ptr,
+ size_t size, int direction)
+{
+ dma_addr_t addr;
+
+ if (direction == DMA_NONE)
+ out_of_line_bug();
+ addr = virt_to_bus(ptr);
+
+ if ((addr+size) & ~*hwdev->dma_mask)
+ out_of_line_bug();
+ return addr;
+}
+
+static inline void dma_unmap_single(struct device *hwdev, dma_addr_t dma_addr,
+ size_t size, int direction)
+{
+ if (direction == DMA_NONE)
+ out_of_line_bug();
+ /* Nothing to do */
+}
+
+#endif
+
+#define dma_map_page(dev,page,offset,size,dir) \
+ dma_map_single((dev), page_address(page)+(offset), (size), (dir))
+
+static inline void dma_sync_single_for_cpu(struct device *hwdev,
+ dma_addr_t dma_handle,
+ size_t size, int direction)
+{
+ if (direction == DMA_NONE)
+ out_of_line_bug();
+
+ if (swiotlb)
+ return swiotlb_sync_single_for_cpu(hwdev,dma_handle,size,direction);
+
+ flush_write_buffers();
+}
+
+static inline void dma_sync_single_for_device(struct device *hwdev,
+ dma_addr_t dma_handle,
+ size_t size, int direction)
+{
+ if (direction == DMA_NONE)
+ out_of_line_bug();
+
+ if (swiotlb)
+ return swiotlb_sync_single_for_device(hwdev,dma_handle,size,direction);
+
+ flush_write_buffers();
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *hwdev,
+ struct scatterlist *sg,
+ int nelems, int direction)
+{
+ if (direction == DMA_NONE)
+ out_of_line_bug();
+
+ if (swiotlb)
+ return swiotlb_sync_sg_for_cpu(hwdev,sg,nelems,direction);
+
+ flush_write_buffers();
+}
+
+static inline void dma_sync_sg_for_device(struct device *hwdev,
+ struct scatterlist *sg,
+ int nelems, int direction)
+{
+ if (direction == DMA_NONE)
+ out_of_line_bug();
+
+ if (swiotlb)
+ return swiotlb_sync_sg_for_device(hwdev,sg,nelems,direction);
+
+ flush_write_buffers();
+}
+
+extern int dma_map_sg(struct device *hwdev, struct scatterlist *sg,
+ int nents, int direction);
+extern void dma_unmap_sg(struct device *hwdev, struct scatterlist *sg,
+ int nents, int direction);
+
+#define dma_unmap_page dma_unmap_single
+
+extern int dma_supported(struct device *hwdev, u64 mask);
+extern int dma_get_cache_alignment(void);
+#define dma_is_consistent(h) 1
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+ if (!dev->dma_mask || !dma_supported(dev, mask))
+ return -EIO;
+ *dev->dma_mask = mask;
+ return 0;
+}
+
+static inline void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction dir)
+{
+ flush_write_buffers();
+}
#endif
diff --git a/include/asm-x86_64/i387.h b/include/asm-x86_64/i387.h
index 229401824d1bb..e613b8b164e45 100644
--- a/include/asm-x86_64/i387.h
+++ b/include/asm-x86_64/i387.h
@@ -39,16 +39,25 @@ static inline int need_signal_i387(struct task_struct *me)
* FPU lazy state save handling...
*/
-#define kernel_fpu_end() stts()
-
#define unlazy_fpu(tsk) do { \
if ((tsk)->thread_info->status & TS_USEDFPU) \
save_init_fpu(tsk); \
} while (0)
+/* Ignore delayed exceptions from user space */
+static inline void tolerant_fwait(void)
+{
+ asm volatile("1: fwait\n"
+ "2:\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 1b,2b\n"
+ " .previous\n");
+}
+
#define clear_fpu(tsk) do { \
if ((tsk)->thread_info->status & TS_USEDFPU) { \
- asm volatile("fnclex ; fwait"); \
+ tolerant_fwait(); \
(tsk)->thread_info->status &= ~TS_USEDFPU; \
stts(); \
} \
@@ -116,6 +125,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
static inline void kernel_fpu_begin(void)
{
struct thread_info *me = current_thread_info();
+ preempt_disable();
if (me->status & TS_USEDFPU) {
asm volatile("rex64 ; fxsave %0 ; fnclex"
: "=m" (me->task->thread.i387.fxsave));
@@ -125,9 +135,15 @@ static inline void kernel_fpu_begin(void)
clts();
}
+static inline void kernel_fpu_end(void)
+{
+ stts();
+ preempt_enable();
+}
+
static inline void save_init_fpu( struct task_struct *tsk )
{
- asm volatile( "fxsave %0 ; fnclex"
+ asm volatile( "rex64 ; fxsave %0 ; fnclex"
: "=m" (tsk->thread.i387.fxsave));
tsk->thread_info->status &= ~TS_USEDFPU;
stts();
diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86_64/ia32.h
index a680d0356ada0..73319a9a8ca5d 100644
--- a/include/asm-x86_64/ia32.h
+++ b/include/asm-x86_64/ia32.h
@@ -78,12 +78,6 @@ struct stat64 {
unsigned long long st_ino;
} __attribute__((packed));
-
-typedef union sigval32 {
- int sival_int;
- unsigned int sival_ptr;
-} sigval_t32;
-
typedef struct siginfo32 {
int si_signo;
int si_errno;
@@ -102,7 +96,7 @@ typedef struct siginfo32 {
struct {
int _tid; /* timer id */
int _overrun; /* overrun count */
- sigval_t32 _sigval; /* same as below */
+ compat_sigval_t _sigval; /* same as below */
int _sys_private; /* not to be passed to user */
int _overrun_incr; /* amount to add to overrun */
} _timer;
@@ -111,7 +105,7 @@ typedef struct siginfo32 {
struct {
unsigned int _pid; /* sender's pid */
unsigned int _uid; /* sender's uid */
- sigval_t32 _sigval;
+ compat_sigval_t _sigval;
} _rt;
/* SIGCHLD */
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
index 1ddce4b4af101..07b49ddd0fda7 100644
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -186,10 +186,30 @@ extern void iounmap(void *addr);
#define __raw_readl readl
#define __raw_readq readq
-#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
+#ifdef CONFIG_UNORDERED_IO
+static inline void __writel(u32 val, void *addr)
+{
+ volatile u32 *target = addr;
+ asm volatile("movnti %1,%0"
+ : "=m" (*target)
+ : "r" (val) : "memory");
+}
+
+static inline void __writeq(u64 val, void *addr)
+{
+ volatile u64 *target = addr;
+ asm volatile("movnti %1,%0"
+ : "=m" (*target)
+ : "r" (val) : "memory");
+}
+#define writeq(val,addr) __writeq((val),(void *)(addr))
+#define writel(val,addr) __writel((val),(void *)(addr))
+#else
#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
#define writeq(b,addr) (*(volatile unsigned long *) (addr) = (b))
+#endif
+#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
@@ -299,11 +319,8 @@ out:
#define flush_write_buffers()
-/* Disable vmerge for now. Need to fix the block layer code
- to check for non iommu addresses first.
- When the IOMMU is force it is safe to enable. */
-extern int iommu_merge;
-#define BIO_VMERGE_BOUNDARY (iommu_merge ? 4096 : 0)
+extern int iommu_bio_merge;
+#define BIO_VMERGE_BOUNDARY iommu_bio_merge
#endif /* __KERNEL__ */
diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
index 2768b7c83ef6d..fb9e6abbd8135 100644
--- a/include/asm-x86_64/mpspec.h
+++ b/include/asm-x86_64/mpspec.h
@@ -166,7 +166,6 @@ enum mp_bustype {
};
extern unsigned char mp_bus_id_to_type [MAX_MP_BUSSES];
extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
-extern cpumask_t pci_bus_to_cpumask [256];
extern unsigned int boot_cpu_physical_apicid;
extern int smp_found_config;
diff --git a/include/asm-x86_64/mtrr.h b/include/asm-x86_64/mtrr.h
index 5e20e10dd8a18..aa4f76c90eaf6 100644
--- a/include/asm-x86_64/mtrr.h
+++ b/include/asm-x86_64/mtrr.h
@@ -71,8 +71,6 @@ struct mtrr_gentry
#ifdef __KERNEL__
-extern char *mtrr_strings[MTRR_NUM_TYPES];
-
/* The following functions are for use by other drivers */
# ifdef CONFIG_MTRR
extern int mtrr_add (unsigned long base, unsigned long size,
diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index ac9e9581d0a30..1b2423fdc9c60 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -44,81 +44,25 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
#include <asm/io.h>
#include <asm/page.h>
-struct pci_dev;
-
extern int iommu_setup(char *opt);
-extern dma_addr_t bad_dma_address;
-#define pci_dma_mapping_error(x) ((x) == bad_dma_address)
-
-/* Allocate and map kernel buffer using consistent mode DMA for a device.
- * hwdev should be valid struct pci_dev pointer for PCI devices,
- * NULL for PCI-like buses (ISA, EISA).
- * Returns non-NULL cpu-view pointer to the buffer if successful and
- * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
- * is undefined.
- */
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t *dma_handle);
-
-/* Free and unmap a consistent DMA buffer.
- * cpu_addr is what was returned from pci_alloc_consistent,
- * size must be the same as what as passed into pci_alloc_consistent,
- * and likewise dma_addr must be the same as what *dma_addrp was set to.
- *
- * References to the memory and mappings associated with cpu_addr/dma_addr
- * past this call are illegal.
- */
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle);
-
-#ifdef CONFIG_SWIOTLB
-extern int swiotlb;
-extern dma_addr_t swiotlb_map_single (struct device *hwdev, void *ptr, size_t size,
- int dir);
-extern void swiotlb_unmap_single (struct device *hwdev, dma_addr_t dev_addr,
- size_t size, int dir);
-extern void swiotlb_sync_single_for_cpu (struct device *hwdev,
- dma_addr_t dev_addr,
- size_t size, int dir);
-extern void swiotlb_sync_single_for_device (struct device *hwdev,
- dma_addr_t dev_addr,
- size_t size, int dir);
-extern void swiotlb_sync_sg_for_cpu (struct device *hwdev,
- struct scatterlist *sg, int nelems,
- int dir);
-extern void swiotlb_sync_sg_for_device (struct device *hwdev,
- struct scatterlist *sg, int nelems,
- int dir);
-extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
- int nents, int direction);
-extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg,
- int nents, int direction);
-
-#endif
-
#ifdef CONFIG_GART_IOMMU
-
-/* Map a single buffer of the indicated size for DMA in streaming mode.
- * The 32-bit bus address to use is returned.
+/* The PCI address space does equal the physical memory
+ * address space. The networking and block device layers use
+ * this boolean for bounce buffer decisions
*
- * Once the device is given the dma address, the device owns this memory
- * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed.
+ * On AMD64 it mostly equals, but we set it to zero to tell some subsystems
+ * that an IOMMU is available.
*/
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
- int direction);
-
-
-void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
- size_t size, int direction);
+#define PCI_DMA_BUS_IS_PHYS (no_iommu ? 1 : 0)
/*
- * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
- * to pci_map_single, but takes a struct page instead of a virtual address
+ * x86-64 always supports DAC, but sometimes it is useful to force
+ * devices through the IOMMU to get automatic sg list merging.
+ * Optional right now.
*/
-
-#define pci_map_page(dev,page,offset,size,dir) \
- pci_map_single((dev), page_address(page)+(offset), (size), (dir))
+extern int iommu_sac_force;
+#define pci_dac_dma_supported(pci_dev, mask) (!iommu_sac_force)
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
@@ -133,113 +77,12 @@ void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
-static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- BUG_ON(direction == PCI_DMA_NONE);
-
-#ifdef CONFIG_SWIOTLB
- if (swiotlb)
- return swiotlb_sync_single_for_cpu(&hwdev->dev,dma_handle,size,direction);
-#endif
-
- flush_write_buffers();
-}
-
-static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- BUG_ON(direction == PCI_DMA_NONE);
-
-#ifdef CONFIG_SWIOTLB
- if (swiotlb)
- return swiotlb_sync_single_for_device(&hwdev->dev,dma_handle,size,direction);
-#endif
-
- flush_write_buffers();
-}
-
-static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
- struct scatterlist *sg,
- int nelems, int direction)
-{
- BUG_ON(direction == PCI_DMA_NONE);
-
-#ifdef CONFIG_SWIOTLB
- if (swiotlb)
- return swiotlb_sync_sg_for_cpu(&hwdev->dev,sg,nelems,direction);
-#endif
- flush_write_buffers();
-}
-
-static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
- struct scatterlist *sg,
- int nelems, int direction)
-{
- BUG_ON(direction == PCI_DMA_NONE);
-
-#ifdef CONFIG_SWIOTLB
- if (swiotlb)
- return swiotlb_sync_sg_for_device(&hwdev->dev,sg,nelems,direction);
-#endif
- flush_write_buffers();
-}
-
-/* The PCI address space does equal the physical memory
- * address space. The networking and block device layers use
- * this boolean for bounce buffer decisions
- *
- * On AMD64 it mostly equals, but we set it to zero to tell some subsystems
- * that an IOMMU is available.
- */
-#define PCI_DMA_BUS_IS_PHYS (no_iommu ? 1 : 0)
-
-/* We lie slightly when the IOMMU is forced to get the device to
- use SAC instead of DAC. */
-#define pci_dac_dma_supported(pci_dev, mask) (force_iommu ? 0 : 1)
-
#else
-static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
- size_t size, int direction)
-{
- dma_addr_t addr;
+/* No IOMMU */
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
- addr = virt_to_bus(ptr);
-
- /*
- * This is gross, but what should I do.
- * Unfortunately drivers do not test the return value of this.
- */
- if ((addr+size) & ~hwdev->dma_mask)
- out_of_line_bug();
- return addr;
-}
-
-static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
- size_t size, int direction)
-{
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
- /* Nothing to do */
-}
-
-static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
- unsigned long offset, size_t size, int direction)
-{
- dma_addr_t addr;
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
- addr = page_to_pfn(page) * PAGE_SIZE + offset;
- if ((addr+size) & ~hwdev->dma_mask)
- out_of_line_bug();
- return addr;
-}
+#define PCI_DMA_BUS_IS_PHYS 1
+#define pci_dac_dma_supported(pci_dev, mask) 1
-/* pci_unmap_{page,single} is a nop so... */
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#define pci_unmap_addr(PTR, ADDR_NAME) (0)
@@ -247,74 +90,9 @@ static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-/* Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
- *
- * If you perform a pci_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so. At the
- * next point you give the PCI dma address back to the card, you
- * must first perform a pci_dma_sync_for_device, and then the
- * device again owns the buffer.
- */
-static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
-}
-
-static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev,
- dma_addr_t dma_handle,
- size_t size, int direction)
-{
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
- flush_write_buffers();
-}
-
-/* Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- *
- * The same as pci_dma_sync_single_* but for a scatter-gather list,
- * same rules and usage.
- */
-static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev,
- struct scatterlist *sg,
- int nelems, int direction)
-{
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
-}
-
-static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
- struct scatterlist *sg,
- int nelems, int direction)
-{
- if (direction == PCI_DMA_NONE)
- out_of_line_bug();
- flush_write_buffers();
-}
-
-#define PCI_DMA_BUS_IS_PHYS 1
-
-#define pci_dac_dma_supported(pci_dev, mask) 1
#endif
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
- int nents, int direction);
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
- int nents, int direction);
-
-#define pci_unmap_page pci_unmap_single
-
-/* Return whether the given PCI device DMA address mask can
- * be supported properly. For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
+#include <asm-generic/pci-dma-compat.h>
static inline dma64_addr_t
pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
@@ -359,7 +137,6 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
/* generic pci stuff */
#ifdef CONFIG_PCI
#include <asm-generic/pci.h>
-#include <linux/dma-mapping.h>
#endif
#endif /* __x8664_PCI_H */
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 934828c8269c0..68fb42d3a3b3c 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -456,9 +456,4 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
-#ifdef CONFIG_SCHED_SMT
-#define ARCH_HAS_SCHED_DOMAIN
-#define ARCH_HAS_SCHED_WAKE_IDLE
-#endif
-
#endif /* __ASM_X86_64_PROCESSOR_H */
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 25faf9faa8285..24e38d7ef90e4 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -82,7 +82,6 @@ extern int unhandled_signal(struct task_struct *tsk, int sig);
extern void select_idle_routine(const struct cpuinfo_x86 *c);
extern void swiotlb_init(void);
-extern int swiotlb;
extern unsigned long max_mapnr;
extern unsigned long end_pfn;
@@ -103,6 +102,8 @@ extern int fallback_aper_force;
extern int iommu_aperture;
extern int iommu_aperture_disabled;
extern int iommu_aperture_allowed;
+extern int fix_aperture;
+extern int force_iommu;
extern void smp_local_timer_interrupt(struct pt_regs * regs);
diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h
new file mode 100644
index 0000000000000..c25270a770e57
--- /dev/null
+++ b/include/asm-x86_64/swiotlb.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_SWIOTLB_H
+#define _ASM_SWTIOLB_H 1
+
+#include <linux/config.h>
+
+/* SWIOTLB interface */
+
+extern dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size,
+ int dir);
+extern void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, int dir);
+extern void swiotlb_sync_single_for_cpu(struct device *hwdev,
+ dma_addr_t dev_addr,
+ size_t size, int dir);
+extern void swiotlb_sync_single_for_device(struct device *hwdev,
+ dma_addr_t dev_addr,
+ size_t size, int dir);
+extern void swiotlb_sync_sg_for_cpu(struct device *hwdev,
+ struct scatterlist *sg, int nelems,
+ int dir);
+extern void swiotlb_sync_sg_for_device(struct device *hwdev,
+ struct scatterlist *sg, int nelems,
+ int dir);
+extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg,
+ int nents, int direction);
+extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg,
+ int nents, int direction);
+extern int swiotlb_dma_mapping_error(dma_addr_t dma_addr);
+
+#ifdef CONFIG_SWIOTLB
+extern int swiotlb;
+#else
+#define swiotlb 0
+#endif
+
+#endif
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index 6abaf66e6f44b..6671eb65500bb 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -297,11 +297,11 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define mb() asm volatile("mfence":::"memory")
#define rmb() asm volatile("lfence":::"memory")
-/* could use SFENCE here, but it would be only needed for unordered SSE
- store instructions and we always do an explicit sfence with them currently.
- the ordering of normal stores is serialized enough. Just make it a compile
- barrier. */
+#ifdef CONFIG_UNORDERED_IO
+#define wmb() asm volatile("sfence" ::: "memory")
+#else
#define wmb() asm volatile("" ::: "memory")
+#endif
#define read_barrier_depends() do {} while(0)
#define set_mb(var, value) do { xchg(&var, value); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index dbc3f15792bd2..84f24e7a77347 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -14,18 +14,23 @@ extern cpumask_t cpu_online_map;
extern unsigned char cpu_to_node[];
extern cpumask_t node_to_cpumask[];
+extern cpumask_t pci_bus_to_cpumask[];
#define cpu_to_node(cpu) (cpu_to_node[cpu])
#define parent_node(node) (node)
#define node_to_first_cpu(node) (__ffs(node_to_cpumask[node]))
#define node_to_cpumask(node) (node_to_cpumask[node])
-static inline cpumask_t pcibus_to_cpumask(int bus)
+static inline cpumask_t __pcibus_to_cpumask(int bus)
{
+ cpumask_t busmask = pci_bus_to_cpumask[bus];
+ cpumask_t online = cpu_online_map;
cpumask_t res;
- cpus_and(res, pci_bus_to_cpumask[bus], cpu_online_map);
+ cpus_and(res, busmask, online);
return res;
}
+/* broken generic file uses #ifndef later on this */
+#define pcibus_to_cpumask(bus) __pcibus_to_cpumask(bus)
#define NODE_BALANCE_RATE 30 /* CHECKME */
diff --git a/include/linux/adfs_fs_i.h b/include/linux/adfs_fs_i.h
index 6341f7059b0b0..cb543034e54fa 100644
--- a/include/linux/adfs_fs_i.h
+++ b/include/linux/adfs_fs_i.h
@@ -17,7 +17,7 @@ struct adfs_inode_info {
__u32 execaddr; /* RISC OS exec address */
unsigned int filetype; /* RISC OS file type */
unsigned int attr; /* RISC OS permissions */
- int stamped:1; /* RISC OS file has date/time */
+ unsigned int stamped:1; /* RISC OS file has date/time */
struct inode vfs_inode;
};
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 461a3b0736e00..a4d5af907f900 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -52,7 +52,7 @@ struct kiocb {
struct file *ki_filp;
struct kioctx *ki_ctx; /* may be NULL for sync ops */
int (*ki_cancel)(struct kiocb *, struct io_event *);
- long (*ki_retry)(struct kiocb *);
+ ssize_t (*ki_retry)(struct kiocb *);
void (*ki_dtor)(struct kiocb *);
struct list_head ki_list; /* the aio core uses this
@@ -64,6 +64,16 @@ struct kiocb {
} ki_obj;
__u64 ki_user_data; /* user's data for completion */
loff_t ki_pos;
+ /* State that we remember to be able to restart/retry */
+ unsigned short ki_opcode;
+ size_t ki_nbytes; /* copy of iocb->aio_nbytes */
+ char __user *ki_buf; /* remaining iocb->aio_buf */
+ size_t ki_left; /* remaining bytes */
+ wait_queue_t ki_wait;
+ long ki_retried; /* just for testing */
+ long ki_kicked; /* just for testing */
+ long ki_queued; /* just for testing */
+
void *private;
};
@@ -79,6 +89,8 @@ struct kiocb {
(x)->ki_cancel = NULL; \
(x)->ki_dtor = NULL; \
(x)->ki_obj.tsk = tsk; \
+ (x)->ki_user_data = 0; \
+ init_wait((&(x)->ki_wait)); \
} while (0)
#define AIO_RING_MAGIC 0xa10a10a1
@@ -161,6 +173,20 @@ int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
#define get_ioctx(kioctx) do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0)
#define put_ioctx(kioctx) do { if (unlikely(atomic_dec_and_test(&(kioctx)->users))) __put_ioctx(kioctx); else if (unlikely(atomic_read(&(kioctx)->users) < 0)) BUG(); } while (0)
+#define in_aio() !is_sync_wait(current->io_wait)
+/* may be used for debugging */
+#define warn_if_async() \
+do { \
+ if (in_aio()) { \
+ printk(KERN_ERR "%s(%s:%d) called in async context!\n", \
+ __FUNCTION__, __FILE__, __LINE__); \
+ dump_stack(); \
+ } \
+} while (0)
+
+#define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait)
+#define is_retried_kiocb(iocb) ((iocb)->ki_retried > 1)
+
#include <linux/aio_abi.h>
static inline struct kiocb *list_kiocb(struct list_head *h)
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index f22efded164a5..eab2932c613c1 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -49,12 +49,12 @@ typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
struct buffer_head {
/* First cache line: */
unsigned long b_state; /* buffer state bitmap (see above) */
- atomic_t b_count; /* users using this block */
struct buffer_head *b_this_page;/* circular list of page's buffers */
struct page *b_page; /* the page this bh is mapped to */
+ atomic_t b_count; /* users using this block */
+ u32 b_size; /* block size */
sector_t b_blocknr; /* block number */
- u32 b_size; /* block size */
char *b_data; /* pointer to data block */
struct block_device *b_bdev;
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 7109aa6e501ef..1ff1e85f6e594 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -73,6 +73,7 @@
* inside a macro, the way we do the other calls.
*/
+#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/bitmap.h>
#include <asm/bug.h>
@@ -207,13 +208,13 @@ static inline void __cpus_shift_left(cpumask_t *dstp,
#define first_cpu(src) __first_cpu(&(src), NR_CPUS)
static inline int __first_cpu(const cpumask_t *srcp, int nbits)
{
- return find_first_bit(srcp->bits, nbits);
+ return min_t(int, nbits, find_first_bit(srcp->bits, nbits));
}
#define next_cpu(n, src) __next_cpu((n), &(src), NR_CPUS)
static inline int __next_cpu(int n, const cpumask_t *srcp, int nbits)
{
- return find_next_bit(srcp->bits, nbits, n+1);
+ return min_t(int, nbits, find_next_bit(srcp->bits, nbits, n+1));
}
#define cpumask_of_cpu(cpu) \
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 66e27328434b5..b378e57b2743b 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -33,8 +33,8 @@ struct vfsmount;
*/
struct qstr {
unsigned int hash;
- const unsigned char *name;
unsigned int len;
+ const unsigned char *name;
};
struct dentry_stat_t {
@@ -101,11 +101,11 @@ struct dentry {
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
- int d_mounted;
void *d_fsdata; /* fs-specific data */
struct rcu_head d_rcu;
struct dcookie_struct *d_cookie; /* cookie, if any */
struct hlist_node d_hash; /* lookup hash list */
+ int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
diff --git a/include/linux/device.h b/include/linux/device.h
index 49d3865aa27b3..fd7e27c79467c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -59,7 +59,6 @@ struct bus_type {
struct driver_attribute * drv_attrs;
int (*match)(struct device * dev, struct device_driver * drv);
- struct device * (*add) (struct device * parent, char * bus_id);
int (*hotplug) (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
int (*suspend)(struct device * dev, u32 state);
diff --git a/include/linux/errno.h b/include/linux/errno.h
index a1f948f0a2079..d90b80f9b28c7 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -22,6 +22,7 @@
#define EBADTYPE 527 /* Type not supported by server */
#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
#define EIOCBQUEUED 529 /* iocb queued, will get completion event */
+#define EIOCBRETRY 530 /* iocb queued, will trigger a retry */
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a7631bd33db10..aecce55e4f88f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1571,6 +1571,39 @@ static inline ino_t parent_ino(struct dentry *dentry)
/* kernel/fork.c */
extern int unshare_files(void);
+/* Transaction based IO helpers */
+
+/*
+ * An argresp is stored in an allocated page and holds the
+ * size of the argument or response, along with its content
+ */
+struct simple_transaction_argresp {
+ ssize_t size;
+ char data[0];
+};
+
+#define SIMPLE_TRANSACTION_LIMIT (PAGE_SIZE - sizeof(struct simple_transaction_argresp))
+
+char *simple_transaction_get(struct file *file, const char __user *buf,
+ size_t size);
+ssize_t simple_transaction_read(struct file *file, char __user *buf,
+ size_t size, loff_t *pos);
+int simple_transaction_release(struct inode *inode, struct file *file);
+
+static inline void simple_transaction_set(struct file *file, size_t n)
+{
+ struct simple_transaction_argresp *ar = file->private_data;
+
+ BUG_ON(n > SIMPLE_TRANSACTION_LIMIT);
+
+ /*
+ * The barrier ensures that ar->size will really remain zero until
+ * ar->data is ready for reading.
+ */
+ smp_mb();
+ ar->size = n;
+}
+
#ifdef CONFIG_SECURITY
static inline char *alloc_secdata(void)
{
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 884d18df67163..d69d9929d4f30 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -100,7 +100,7 @@ struct gendisk {
struct timer_rand_state *random;
int policy;
- unsigned sync_io; /* RAID */
+ atomic_t sync_io; /* RAID */
unsigned long stamp, stamp_idle;
int in_flight;
#ifdef CONFIG_SMP
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 8980d1fd71818..600f83c80aad1 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -73,6 +73,11 @@ struct vm_area_struct;
* For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets
* optimized to &contig_page_data at compile-time.
*/
+
+#ifndef HAVE_ARCH_FREE_PAGE
+static inline void arch_free_page(struct page *page, int order) { }
+#endif
+
extern struct page *
FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *));
diff --git a/include/linux/ghash.h b/include/linux/ghash.h
new file mode 100644
index 0000000000000..2d5583fe7c26f
--- /dev/null
+++ b/include/linux/ghash.h
@@ -0,0 +1,236 @@
+/*
+ * include/linux/ghash.h -- generic hashing with fuzzy retrieval
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ *
+ * The algorithms implemented here seem to be a completely new invention,
+ * and I'll publish the fundamentals in a paper.
+ */
+
+#ifndef _GHASH_H
+#define _GHASH_H
+/* HASHSIZE _must_ be a power of two!!! */
+
+
+#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+ TYPE * hashtable[HASHSIZE];\
+ TYPE * sorted_list;\
+ int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+ TYPE * next_hash;\
+ TYPE * prev_hash;\
+ TYPE * next_sorted;\
+ TYPE * prev_sorted;\
+};
+
+#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ int ix = HASHFN(elem->KEY);\
+ TYPE ** base = &tbl->hashtable[ix];\
+ TYPE * ptr = *base;\
+ TYPE * prev = NULL;\
+\
+ tbl->nr_entries++;\
+ while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+ base = &ptr->PTRS.next_hash;\
+ prev = ptr;\
+ ptr = *base;\
+ }\
+ elem->PTRS.next_hash = ptr;\
+ elem->PTRS.prev_hash = prev;\
+ if(ptr) {\
+ ptr->PTRS.prev_hash = elem;\
+ }\
+ *base = elem;\
+\
+ ptr = prev;\
+ if(!ptr) {\
+ ptr = tbl->sorted_list;\
+ prev = NULL;\
+ } else {\
+ prev = ptr->PTRS.prev_sorted;\
+ }\
+ while(ptr) {\
+ TYPE * next = ptr->PTRS.next_hash;\
+ if(next && KEYCMP(next->KEY, elem->KEY)) {\
+ prev = ptr;\
+ ptr = next;\
+ } else if(KEYCMP(ptr->KEY, elem->KEY)) {\
+ prev = ptr;\
+ ptr = ptr->PTRS.next_sorted;\
+ } else\
+ break;\
+ }\
+ elem->PTRS.next_sorted = ptr;\
+ elem->PTRS.prev_sorted = prev;\
+ if(ptr) {\
+ ptr->PTRS.prev_sorted = elem;\
+ }\
+ if(prev) {\
+ prev->PTRS.next_sorted = elem;\
+ } else {\
+ tbl->sorted_list = elem;\
+ }\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ TYPE * next = elem->PTRS.next_hash;\
+ TYPE * prev = elem->PTRS.prev_hash;\
+\
+ tbl->nr_entries--;\
+ if(next)\
+ next->PTRS.prev_hash = prev;\
+ if(prev)\
+ prev->PTRS.next_hash = next;\
+ else {\
+ int ix = HASHFN(elem->KEY);\
+ tbl->hashtable[ix] = next;\
+ }\
+\
+ next = elem->PTRS.next_sorted;\
+ prev = elem->PTRS.prev_sorted;\
+ if(next)\
+ next->PTRS.prev_sorted = prev;\
+ if(prev)\
+ prev->PTRS.next_sorted = next;\
+ else\
+ tbl->sorted_list = next;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+ int ix = hashfn(pos);\
+ TYPE * ptr = tbl->hashtable[ix];\
+ while(ptr && KEYCMP(ptr->KEY, pos))\
+ ptr = ptr->PTRS.next_hash;\
+ if(ptr && !KEYEQ(ptr->KEY, pos))\
+ ptr = NULL;\
+ return ptr;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+ int ix;\
+ int offset;\
+ TYPE * ptr;\
+ TYPE * next;\
+\
+ ptr = tbl->sorted_list;\
+ if(!ptr || KEYCMP(pos, ptr->KEY))\
+ return NULL;\
+ ix = HASHFN(pos);\
+ offset = HASHSIZE;\
+ do {\
+ offset >>= 1;\
+ next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\
+ if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\
+ && KEYCMP(ptr->KEY, next->KEY))\
+ ptr = next;\
+ } while(offset);\
+\
+ for(;;) {\
+ next = ptr->PTRS.next_hash;\
+ if(next) {\
+ if(KEYCMP(next->KEY, pos)) {\
+ ptr = next;\
+ continue;\
+ }\
+ }\
+ next = ptr->PTRS.next_sorted;\
+ if(next && KEYCMP(next->KEY, pos)) {\
+ ptr = next;\
+ continue;\
+ }\
+ return ptr;\
+ }\
+ return NULL;\
+}
+
+/* LINKAGE - empty or "static", depending on whether you want the definitions to
+ * be public or not
+ * NAME - a string to stick in names to make this hash table type distinct from
+ * any others
+ * HASHSIZE - number of buckets
+ * TYPE - type of data contained in the buckets - must be a structure, one
+ * field is of type NAME_ptrs, another is the hash key
+ * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that
+ * field
+ * KEYTYPE - type of the key field within TYPE
+ * KEY - name of the key field within TYPE
+ * KEYCMP - pointer to function that compares KEYTYPEs to each other - the
+ * prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal,
+ * non-zero for not equal
+ * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE),
+ * it returns a number in the range 0 ... HASHSIZE - 1
+ * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call
+ * DEF_HASH.
+ */
+
+#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+ TYPE * hashtable[HASHSIZE];\
+ int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+ TYPE * next_hash;\
+ TYPE * prev_hash;\
+};
+
+#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ int ix = HASHFN(elem->KEY);\
+ TYPE ** base = &tbl->hashtable[ix];\
+ TYPE * ptr = *base;\
+ TYPE * prev = NULL;\
+\
+ tbl->nr_entries++;\
+ while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+ base = &ptr->PTRS.next_hash;\
+ prev = ptr;\
+ ptr = *base;\
+ }\
+ elem->PTRS.next_hash = ptr;\
+ elem->PTRS.prev_hash = prev;\
+ if(ptr) {\
+ ptr->PTRS.prev_hash = elem;\
+ }\
+ *base = elem;\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ TYPE * next = elem->PTRS.next_hash;\
+ TYPE * prev = elem->PTRS.prev_hash;\
+\
+ tbl->nr_entries--;\
+ if(next)\
+ next->PTRS.prev_hash = prev;\
+ if(prev)\
+ prev->PTRS.next_hash = next;\
+ else {\
+ int ix = HASHFN(elem->KEY);\
+ tbl->hashtable[ix] = next;\
+ }\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+ int ix = HASHFN(pos);\
+ TYPE * ptr = tbl->hashtable[ix];\
+ while(ptr && KEYCMP(ptr->KEY, pos))\
+ ptr = ptr->PTRS.next_hash;\
+ return ptr;\
+}
+
+#endif
diff --git a/include/linux/highuid.h b/include/linux/highuid.h
index 811cac9dba17b..53ecac3905e8d 100644
--- a/include/linux/highuid.h
+++ b/include/linux/highuid.h
@@ -44,8 +44,8 @@ extern void __bad_gid(void);
#ifdef CONFIG_UID16
/* prevent uid mod 65536 effect by returning a default value for high UIDs */
-#define high2lowuid(uid) ((uid) > 65535 ? (old_uid_t)overflowuid : (old_uid_t)(uid))
-#define high2lowgid(gid) ((gid) > 65535 ? (old_gid_t)overflowgid : (old_gid_t)(gid))
+#define high2lowuid(uid) ((uid) & ~0xFFFF ? (old_uid_t)overflowuid : (old_uid_t)(uid))
+#define high2lowgid(gid) ((gid) & ~0xFFFF ? (old_gid_t)overflowgid : (old_gid_t)(gid))
/*
* -1 is different in 16 bits than it is in 32 bits
* these macros are used by chown(), setreuid(), ...,
@@ -89,8 +89,8 @@ extern int fs_overflowgid;
* Since these macros are used in architectures that only need limited
* 16-bit UID back compatibility, we won't use old_uid_t and old_gid_t
*/
-#define fs_high2lowuid(uid) ((uid) > 65535 ? (uid16_t)fs_overflowuid : (uid16_t)(uid))
-#define fs_high2lowgid(gid) ((gid) > 65535 ? (gid16_t)fs_overflowgid : (gid16_t)(gid))
+#define fs_high2lowuid(uid) ((uid) & ~0xFFFF ? (uid16_t)fs_overflowuid : (uid16_t)(uid))
+#define fs_high2lowgid(gid) ((gid) & ~0xFFFF ? (gid16_t)fs_overflowgid : (gid16_t)(gid))
#define low_16_bits(x) ((x) & 0xFFFF)
#define high_16_bits(x) (((x) & 0xFFFF0000) >> 16)
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 58d6e606d27d7..fd1b6eb94a5f1 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -105,7 +105,7 @@ struct __fdb_entry
#include <linux/netdevice.h>
extern void brioctl_set(int (*ioctl_hook)(unsigned int, void __user *));
-extern int (*br_handle_frame_hook)(struct sk_buff *skb);
+extern int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
extern int (*br_should_route_hook)(struct sk_buff **pskb);
#endif
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 6360d225884c0..4ec94fa8163ff 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -19,6 +19,7 @@
#include <linux/list.h>
#include <linux/sysfs.h>
#include <linux/rwsem.h>
+#include <linux/kref.h>
#include <asm/atomic.h>
#define KOBJ_NAME_LEN 20
@@ -26,7 +27,7 @@
struct kobject {
char * k_name;
char name[KOBJ_NAME_LEN];
- atomic_t refcount;
+ struct kref kref;
struct list_head entry;
struct kobject * parent;
struct kset * kset;
@@ -58,6 +59,8 @@ extern void kobject_put(struct kobject *);
extern void kobject_hotplug(const char *action, struct kobject *);
+extern char * kobject_get_path(struct kset *, struct kobject *, int);
+
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
diff --git a/include/linux/kref.h b/include/linux/kref.h
index 82284b7e730be..119c74eca194a 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -18,15 +18,12 @@
#include <linux/types.h>
#include <asm/atomic.h>
-
struct kref {
atomic_t refcount;
- void (*release)(struct kref *kref);
};
-void kref_init(struct kref *kref, void (*release)(struct kref *));
-struct kref *kref_get(struct kref *kref);
-void kref_put(struct kref *kref);
-
+void kref_init(struct kref *kref);
+void kref_get(struct kref *kref);
+void kref_put(struct kref *kref, void (*release) (struct kref *kref));
#endif /* _KREF_H_ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b7859da6d3339..42dca234d1663 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -26,6 +26,12 @@ extern void * high_memory;
extern unsigned long vmalloc_earlyreserve;
extern int page_cluster;
+#ifdef CONFIG_SYSCTL
+extern int sysctl_legacy_va_layout;
+#else
+#define sysctl_legacy_va_layout 0
+#endif
+
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -195,21 +201,21 @@ struct page {
page_flags_t flags; /* Atomic flags, some possibly
* updated asynchronously */
atomic_t _count; /* Usage count, see below. */
- unsigned int mapcount; /* Count of ptes mapped in mms,
+ atomic_t _mapcount; /* Count of ptes mapped in mms,
* to show when page is mapped
- * & limit reverse map searches,
- * protected by PG_maplock.
+ * & limit reverse map searches.
*/
unsigned long private; /* Mapping-private opaque data:
* usually used for buffer_heads
* if PagePrivate set; used for
* swp_entry_t if PageSwapCache
*/
- struct address_space *mapping; /* If PG_anon clear, points to
+ struct address_space *mapping; /* If low bit clear, points to
* inode address_space, or NULL.
* If page mapped as anonymous
- * memory, PG_anon is set, and
- * it points to anon_vma object.
+ * memory, low bit is set, and
+ * it points to anon_vma object:
+ * see PAGE_MAPPING_ANON below.
*/
pgoff_t index; /* Our offset within mapping. */
struct list_head lru; /* Pageout list, eg. active_list
@@ -433,24 +439,32 @@ void page_address_init(void);
/*
* On an anonymous page mapped into a user virtual memory area,
- * page->mapping points to its anon_vma, not to a struct address_space.
+ * page->mapping points to its anon_vma, not to a struct address_space;
+ * with the PAGE_MAPPING_ANON bit set to distinguish it.
*
* Please note that, confusingly, "page_mapping" refers to the inode
* address_space which maps the page from disk; whereas "page_mapped"
* refers to user virtual address space into which the page is mapped.
*/
+#define PAGE_MAPPING_ANON 1
+
extern struct address_space swapper_space;
static inline struct address_space *page_mapping(struct page *page)
{
- struct address_space *mapping = NULL;
+ struct address_space *mapping = page->mapping;
if (unlikely(PageSwapCache(page)))
mapping = &swapper_space;
- else if (likely(!PageAnon(page)))
- mapping = page->mapping;
+ else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
+ mapping = NULL;
return mapping;
}
+static inline int PageAnon(struct page *page)
+{
+ return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
+}
+
/*
* Return the pagecache index of the passed page. Regular pagecache pages
* use ->index whereas swapcache pages use ->private
@@ -463,11 +477,26 @@ static inline pgoff_t page_index(struct page *page)
}
/*
+ * The atomic page->_mapcount, like _count, starts from -1:
+ * so that transitions both from it and to it can be tracked,
+ * using atomic_inc_and_test and atomic_add_negative(-1).
+ */
+static inline void reset_page_mapcount(struct page *page)
+{
+ atomic_set(&(page)->_mapcount, -1);
+}
+
+static inline int page_mapcount(struct page *page)
+{
+ return atomic_read(&(page)->_mapcount) + 1;
+}
+
+/*
* Return true if this page is mapped into pagetables.
*/
static inline int page_mapped(struct page *page)
{
- return page->mapcount != 0;
+ return atomic_read(&(page)->_mapcount) >= 0;
}
/*
@@ -599,11 +628,10 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long a
}
extern void free_area_init(unsigned long * zones_size);
-extern void free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
+extern void free_area_init_node(int nid, pg_data_t *pgdat,
unsigned long * zones_size, unsigned long zone_start_pfn,
unsigned long *zholes_size);
-extern void memmap_init_zone(struct page *, unsigned long, int,
- unsigned long, unsigned long);
+extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long);
extern void mem_init(void);
extern void show_mem(void);
extern void si_meminfo(struct sysinfo * val);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 47431567a76fa..7c36a10f6720a 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -272,6 +272,8 @@ typedef struct pglist_data {
extern int numnodes;
extern struct pglist_data *pgdat_list;
+void __get_zone_counts(unsigned long *active, unsigned long *inactive,
+ unsigned long *free, struct pglist_data *pgdat);
void get_zone_counts(unsigned long *active, unsigned long *inactive,
unsigned long *free);
void build_all_zonelists(void);
diff --git a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h
index be6bb082d0ba4..b34e4ce9ee6a5 100644
--- a/include/linux/netfilter_ipv4/ip_nat_helper.h
+++ b/include/linux/netfilter_ipv4/ip_nat_helper.h
@@ -44,6 +44,9 @@ extern void ip_nat_helper_unregister(struct ip_nat_helper *me);
extern struct ip_nat_helper *
ip_nat_find_helper(const struct ip_conntrack_tuple *tuple);
+extern struct ip_nat_helper *
+__ip_nat_find_helper(const struct ip_conntrack_tuple *tuple);
+
/* These return true or false. */
extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
struct ip_conntrack *ct,
diff --git a/include/linux/node.h b/include/linux/node.h
index 6b8d64c16e5ea..6e0a697e594ea 100644
--- a/include/linux/node.h
+++ b/include/linux/node.h
@@ -23,7 +23,6 @@
#include <linux/cpumask.h>
struct node {
- cpumask_t cpumap; /* Bitmap of CPUs on the Node */
struct sys_device sysdev;
};
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index c6f5063f0addf..97325175d93bd 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -69,14 +69,11 @@
#define PG_private 12 /* Has something at ->private */
#define PG_writeback 13 /* Page is under writeback */
#define PG_nosave 14 /* Used for system suspend/resume */
-#define PG_maplock 15 /* Lock bit for rmap to ptes */
+#define PG_compound 15 /* Part of a compound page */
#define PG_swapcache 16 /* Swap page: swp_entry_t in private */
#define PG_mappedtodisk 17 /* Has blocks allocated on-disk */
#define PG_reclaim 18 /* To be reclaimed asap */
-#define PG_compound 19 /* Part of a compound page */
-
-#define PG_anon 20 /* Anonymous: anon_vma in mapping */
/*
@@ -236,6 +233,7 @@ extern unsigned long __read_page_state(unsigned offset);
#define PageReserved(page) test_bit(PG_reserved, &(page)->flags)
#define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags)
#define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags)
+#define __ClearPageReserved(page) __clear_bit(PG_reserved, &(page)->flags)
#define SetPagePrivate(page) set_bit(PG_private, &(page)->flags)
#define ClearPagePrivate(page) clear_bit(PG_private, &(page)->flags)
@@ -292,10 +290,6 @@ extern unsigned long __read_page_state(unsigned offset);
#define SetPageCompound(page) set_bit(PG_compound, &(page)->flags)
#define ClearPageCompound(page) clear_bit(PG_compound, &(page)->flags)
-#define PageAnon(page) test_bit(PG_anon, &(page)->flags)
-#define SetPageAnon(page) set_bit(PG_anon, &(page)->flags)
-#define ClearPageAnon(page) clear_bit(PG_anon, &(page)->flags)
-
#ifdef CONFIG_SWAP
#define PageSwapCache(page) test_bit(PG_swapcache, &(page)->flags)
#define SetPageSwapCache(page) set_bit(PG_swapcache, &(page)->flags)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 866919694dbcf..3f76ca047d2f5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -712,7 +712,7 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct reso
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
extern void pci_dev_put(struct pci_dev *dev);
-
+extern void pci_remove_bus(struct pci_bus *b);
extern void pci_remove_bus_device(struct pci_dev *dev);
/* Generic PCI functions exported to card drivers */
diff --git a/include/linux/personality.h b/include/linux/personality.h
index 9b009b6754f6a..7efc05ea7efc7 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -30,6 +30,7 @@ extern int abi_fake_utsname;
*/
enum {
MMAP_PAGE_ZERO = 0x0100000,
+ ADDR_COMPAT_LAYOUT = 0x0200000,
READ_IMPLIES_EXEC = 0x0400000,
ADDR_LIMIT_32BIT = 0x0800000,
SHORT_INODE = 0x1000000,
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index 9c06e776cfc22..d9e292ebe417b 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -74,7 +74,6 @@ extern void md_write_start(mddev_t *mddev);
extern void md_write_end(mddev_t *mddev);
extern void md_handle_safemode(mddev_t *mddev);
extern void md_done_sync(mddev_t *mddev, int blocks, int ok);
-extern void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors);
extern void md_error (mddev_t *mddev, mdk_rdev_t *rdev);
extern void md_unplug_mddev(mddev_t *mddev);
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index faa400cf25e45..945346ec2c102 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -24,7 +24,8 @@
#define HSM 6UL
#define MULTIPATH 7UL
#define RAID6 8UL
-#define MAX_PERSONALITY 9UL
+#define RAID10 9UL
+#define MAX_PERSONALITY 10UL
#define LEVEL_MULTIPATH (-4)
#define LEVEL_LINEAR (-1)
@@ -43,6 +44,7 @@ static inline int pers_to_level (int pers)
case RAID1: return 1;
case RAID5: return 5;
case RAID6: return 6;
+ case RAID10: return 10;
}
BUG();
return MD_RESERVED;
@@ -60,6 +62,7 @@ static inline int level_to_pers (int level)
case 4:
case 5: return RAID5;
case 6: return RAID6;
+ case 10: return RAID10;
}
return MD_RESERVED;
}
@@ -216,6 +219,7 @@ struct mddev_s
unsigned long resync_mark; /* a recent timestamp */
sector_t resync_mark_cnt;/* blocks written at resync_mark */
+ sector_t resync_max_sectors; /* may be set by personality */
/* recovery/resync flags
* NEEDED: we might need to start a resync/recover
* RUNNING: a thread is running, or about to be started
@@ -263,6 +267,11 @@ static inline void rdev_dec_pending(mdk_rdev_t *rdev, mddev_t *mddev)
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
}
+static inline void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors)
+{
+ atomic_add(nr_sectors, &bdev->bd_contains->bd_disk->sync_io);
+}
+
struct mdk_personality_s
{
char *name;
diff --git a/include/linux/raid/raid10.h b/include/linux/raid/raid10.h
new file mode 100644
index 0000000000000..60708789c8f97
--- /dev/null
+++ b/include/linux/raid/raid10.h
@@ -0,0 +1,103 @@
+#ifndef _RAID10_H
+#define _RAID10_H
+
+#include <linux/raid/md.h>
+
+typedef struct mirror_info mirror_info_t;
+
+struct mirror_info {
+ mdk_rdev_t *rdev;
+ sector_t head_position;
+};
+
+typedef struct r10bio_s r10bio_t;
+
+struct r10_private_data_s {
+ mddev_t *mddev;
+ mirror_info_t *mirrors;
+ int raid_disks;
+ int working_disks;
+ spinlock_t device_lock;
+
+ /* geometry */
+ int near_copies; /* number of copies layed out raid0 style */
+ int far_copies; /* number of copies layed out
+ * at large strides across drives
+ */
+ int copies; /* near_copies * far_copies.
+ * must be <= raid_disks
+ */
+ sector_t stride; /* distance between far copies.
+ * This is size / far_copies
+ */
+
+ int chunk_shift; /* shift from chunks to sectors */
+ sector_t chunk_mask;
+
+ struct list_head retry_list;
+ /* for use when syncing mirrors: */
+
+ spinlock_t resync_lock;
+ int nr_pending;
+ int barrier;
+ sector_t next_resync;
+
+ wait_queue_head_t wait_idle;
+ wait_queue_head_t wait_resume;
+
+ mempool_t *r10bio_pool;
+ mempool_t *r10buf_pool;
+};
+
+typedef struct r10_private_data_s conf_t;
+
+/*
+ * this is the only point in the RAID code where we violate
+ * C type safety. mddev->private is an 'opaque' pointer.
+ */
+#define mddev_to_conf(mddev) ((conf_t *) mddev->private)
+
+/*
+ * this is our 'private' RAID10 bio.
+ *
+ * it contains information about what kind of IO operations were started
+ * for this RAID10 operation, and about their status:
+ */
+
+struct r10bio_s {
+ atomic_t remaining; /* 'have we finished' count,
+ * used from IRQ handlers
+ */
+ sector_t sector; /* virtual sector number */
+ int sectors;
+ unsigned long state;
+ mddev_t *mddev;
+ /*
+ * original bio going to /dev/mdx
+ */
+ struct bio *master_bio;
+ /*
+ * if the IO is in READ direction, then this is where we read
+ */
+ int read_slot;
+
+ struct list_head retry_list;
+ /*
+ * if the IO is in WRITE direction, then multiple bios are used,
+ * one for each copy.
+ * When resyncing we also use one for each copy.
+ * When reconstructing, we use 2 bios, one for read, one for write.
+ * We choose the number when they are allocated.
+ */
+ struct {
+ struct bio *bio;
+ sector_t addr;
+ int devnum;
+ } devs[0];
+};
+
+/* bits for r10bio.state */
+#define R10BIO_Uptodate 0
+#define R10BIO_IsSync 1
+#define R10BIO_IsRecover 2
+#endif
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index e3148341f476c..291d36c9e987f 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -9,11 +9,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-#define page_map_lock(page) \
- bit_spin_lock(PG_maplock, (unsigned long *)&(page)->flags)
-#define page_map_unlock(page) \
- bit_spin_unlock(PG_maplock, (unsigned long *)&(page)->flags)
-
/*
* The anon_vma heads a list of private "related" vmas, to scan if
* an anonymous page pointing to this anon_vma needs to be unmapped:
@@ -87,24 +82,27 @@ void page_remove_rmap(struct page *);
*/
static inline void page_dup_rmap(struct page *page)
{
- page_map_lock(page);
- page->mapcount++;
- page_map_unlock(page);
+ atomic_inc(&page->_mapcount);
}
/*
* Called from mm/vmscan.c to handle paging out
*/
-int page_referenced(struct page *);
+int page_referenced(struct page *, int is_locked);
int try_to_unmap(struct page *);
+/*
+ * Used by swapoff to help locate where page is expected in vma.
+ */
+unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
+
#else /* !CONFIG_MMU */
#define anon_vma_init() do {} while (0)
#define anon_vma_prepare(vma) (0)
#define anon_vma_link(vma) do {} while (0)
-#define page_referenced(page) TestClearPageReferenced(page)
+#define page_referenced(page,l) TestClearPageReferenced(page)
#define try_to_unmap(page) SWAP_FAIL
#endif /* CONFIG_MMU */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 58c6429ccdf7f..f92c35c07faca 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -561,6 +561,10 @@ enum
#define IFLA_WIRELESS IFLA_WIRELESS
IFLA_PROTINFO, /* Protocol specific information for a link */
#define IFLA_PROTINFO IFLA_PROTINFO
+ IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+ IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
__IFLA_MAX
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 24066551b9668..9db8aa95d492b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -40,7 +40,6 @@ struct exec_domain;
#define CLONE_FS 0x00000200 /* set if fs info shared between processes */
#define CLONE_FILES 0x00000400 /* set if open files shared between processes */
#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */
-#define CLONE_IDLETASK 0x00001000 /* set if new pid should be 0 (kernel only)*/
#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */
@@ -189,10 +188,26 @@ extern int sysctl_max_map_count;
#include <linux/aio.h>
+extern unsigned long
+arch_get_unmapped_area(struct file *, unsigned long, unsigned long,
+ unsigned long, unsigned long);
+extern unsigned long
+arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags);
+extern void arch_unmap_area(struct vm_area_struct *area);
+extern void arch_unmap_area_topdown(struct vm_area_struct *area);
+
+
struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
struct rb_root mm_rb;
struct vm_area_struct * mmap_cache; /* last find_vma result */
+ unsigned long (*get_unmapped_area) (struct file *filp,
+ unsigned long addr, unsigned long len,
+ unsigned long pgoff, unsigned long flags);
+ void (*unmap_area) (struct vm_area_struct *area);
+ unsigned long mmap_base; /* base of mmap area */
unsigned long free_area_cache; /* first hole */
pgd_t * pgd;
atomic_t mm_users; /* How many users with user space? */
@@ -304,7 +319,7 @@ struct signal_struct {
#define MAX_PRIO (MAX_RT_PRIO + 40)
-#define rt_task(p) ((p)->prio < MAX_RT_PRIO)
+#define rt_task(p) (unlikely((p)->prio < MAX_RT_PRIO))
/*
* Some day this will be a full-fledged user tracking system..
@@ -352,6 +367,20 @@ struct k_itimer {
struct timespec wall_to_prev; /* wall_to_monotonic used when set */
};
+#ifdef CONFIG_SCHEDSTATS
+struct sched_info {
+ /* cumulative counters */
+ unsigned long cpu_time, /* time spent on the cpu */
+ run_delay, /* time spent waiting on a runqueue */
+ pcnt; /* # of timeslices run on this cpu */
+
+ /* timestamps */
+ unsigned long last_arrival, /* when we last ran on a cpu */
+ last_queued; /* when we were last queued to run */
+};
+
+extern struct file_operations proc_schedstat_operations;
+#endif
struct io_context; /* See blkdev.h */
void exit_io_context(void);
@@ -414,6 +443,10 @@ struct task_struct {
cpumask_t cpus_allowed;
unsigned int time_slice, first_time_slice;
+#ifdef CONFIG_SCHEDSTATS
+ struct sched_info sched_info;
+#endif
+
struct list_head tasks;
/*
* ptrace_list/ptrace_children forms the list of my children
@@ -527,7 +560,13 @@ struct task_struct {
unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use. */
-
+/*
+ * current io wait handle: wait queue entry to use for io waits
+ * If this thread is processing aio, this points at the waitqueue
+ * inside the currently handled kiocb. It may be NULL (i.e. default
+ * to a stack based synchronous wait) if its doing sync IO.
+ */
+ wait_queue_t *io_wait;
#ifdef CONFIG_NUMA
struct mempolicy *mempolicy;
short il_next; /* could be shared with used_math */
@@ -570,118 +609,6 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
#define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */
#ifdef CONFIG_SMP
-#define SCHED_LOAD_SCALE 128UL /* increase resolution of load */
-
-#define SD_BALANCE_NEWIDLE 1 /* Balance when about to become idle */
-#define SD_BALANCE_EXEC 2 /* Balance on exec */
-#define SD_BALANCE_CLONE 4 /* Balance on clone */
-#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 */
-
-struct sched_group {
- struct sched_group *next; /* Must be a circular list */
- cpumask_t cpumask;
-
- /*
- * CPU power of this group, SCHED_LOAD_SCALE being max power for a
- * single CPU. This should be read only (except for setup). Although
- * it will need to be written to at cpu hot(un)plug time, perhaps the
- * cpucontrol semaphore will provide enough exclusion?
- */
- unsigned long cpu_power;
-};
-
-struct sched_domain {
- /* These fields must be setup */
- struct sched_domain *parent; /* top domain must be null terminated */
- struct sched_group *groups; /* the balancing groups of the domain */
- cpumask_t span; /* span of all CPUs in this domain */
- unsigned long min_interval; /* Minimum balance interval ms */
- unsigned long max_interval; /* Maximum balance interval ms */
- unsigned int busy_factor; /* less balancing by factor if busy */
- unsigned int imbalance_pct; /* No balance until over watermark */
- 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 */
- int flags; /* See SD_* */
-
- /* Runtime fields. */
- unsigned long last_balance; /* init to jiffies. units in jiffies */
- unsigned int balance_interval; /* initialise to 1. units in ms. */
- unsigned int nr_balance_failed; /* initialise to 0 */
-};
-
-/* Common values for SMT siblings */
-#define SD_SIBLING_INIT (struct sched_domain) { \
- .span = CPU_MASK_NONE, \
- .parent = NULL, \
- .groups = NULL, \
- .min_interval = 1, \
- .max_interval = 2, \
- .busy_factor = 8, \
- .imbalance_pct = 110, \
- .cache_hot_time = 0, \
- .cache_nice_tries = 0, \
- .per_cpu_gain = 15, \
- .flags = SD_BALANCE_NEWIDLE \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_CLONE \
- | SD_WAKE_AFFINE \
- | SD_WAKE_IDLE \
- | SD_SHARE_CPUPOWER, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
-}
-
-/* Common values for CPUs */
-#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 = (5*1000000/2), \
- .cache_nice_tries = 1, \
- .per_cpu_gain = 100, \
- .flags = SD_BALANCE_NEWIDLE \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_CLONE \
- | SD_WAKE_AFFINE \
- | SD_WAKE_BALANCE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
-}
-
-#ifdef CONFIG_NUMA
-/* Common values for NUMA nodes */
-#define SD_NODE_INIT (struct sched_domain) { \
- .span = CPU_MASK_NONE, \
- .parent = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_hot_time = (10*1000000), \
- .cache_nice_tries = 1, \
- .per_cpu_gain = 100, \
- .flags = SD_BALANCE_EXEC \
- | SD_BALANCE_CLONE \
- | SD_WAKE_BALANCE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
-}
-#endif
-
-extern void cpu_attach_domain(struct sched_domain *sd, int cpu);
-
extern int set_cpus_allowed(task_t *p, cpumask_t new_mask);
#else
static inline int set_cpus_allowed(task_t *p, cpumask_t new_mask)
@@ -692,10 +619,11 @@ static inline int set_cpus_allowed(task_t *p, cpumask_t new_mask)
extern unsigned long long sched_clock(void);
+/* sched_exec is called by processes performing an exec */
#ifdef CONFIG_SMP
-extern void sched_balance_exec(void);
+extern void sched_exec(void);
#else
-#define sched_balance_exec() {}
+#define sched_exec() {}
#endif
extern void sched_idle_next(void);
@@ -754,16 +682,12 @@ extern void do_timer(struct pt_regs *);
extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state));
extern int FASTCALL(wake_up_process(struct task_struct * tsk));
-extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk));
+extern void FASTCALL(wake_up_new_task(struct task_struct * tsk,
+ unsigned long clone_flags));
#ifdef CONFIG_SMP
extern void kick_process(struct task_struct *tsk);
- extern void FASTCALL(wake_up_forked_thread(struct task_struct * tsk));
#else
static inline void kick_process(struct task_struct *tsk) { }
- static inline void wake_up_forked_thread(struct task_struct * tsk)
- {
- wake_up_forked_process(tsk);
- }
#endif
extern void FASTCALL(sched_fork(task_t * p));
extern void FASTCALL(sched_exit(task_t * p));
@@ -794,6 +718,7 @@ extern void unblock_all_signals(void);
extern void release_task(struct task_struct * p);
extern int send_sig_info(int, struct siginfo *, struct task_struct *);
extern int send_group_sig_info(int, struct siginfo *, struct task_struct *);
+extern int force_sigsegv(int, struct task_struct *);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
extern int kill_pg_info(int, struct siginfo *, pid_t);
@@ -863,8 +788,8 @@ static inline void mmdrop(struct mm_struct * mm)
/* mmput gets rid of the mappings and all user-space */
extern void mmput(struct mm_struct *);
-/* Grab a reference to the mm if its not already going away */
-extern struct mm_struct *mmgrab(struct mm_struct *);
+/* Grab a reference to a task's mm, if it is not already going away */
+extern struct mm_struct *get_task_mm(struct task_struct *task);
/* Remove the current tasks stale references to the old mm_struct */
extern void mm_release(struct task_struct *, struct mm_struct *);
@@ -890,7 +815,7 @@ extern task_t *child_reaper;
extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
-extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
+task_t *fork_idle(int);
extern void set_task_comm(struct task_struct *tsk, char *from);
extern void get_task_comm(char *to, struct task_struct *tsk);
@@ -965,27 +890,7 @@ static inline void task_unlock(struct task_struct *p)
{
spin_unlock(&p->alloc_lock);
}
-
-/**
- * get_task_mm - acquire a reference to the task's mm
- *
- * Returns %NULL if the task has no mm. User must release
- * the mm via mmput() after use.
- */
-static inline struct mm_struct * get_task_mm(struct task_struct * task)
-{
- struct mm_struct * mm;
-
- task_lock(task);
- mm = task->mm;
- if (mm)
- mm = mmgrab(mm);
- task_unlock(task);
-
- return mm;
-}
-
-
+
/* set thread flags in other task's structures
* - see asm/thread_info.h for TIF_xxxx flags available
*/
@@ -1096,6 +1001,17 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
#endif /* CONFIG_SMP */
+#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
+extern void arch_pick_mmap_layout(struct mm_struct *mm);
+#else
+static inline void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+}
+#endif
+
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/shm.h b/include/linux/shm.h
index 1907355c0eb14..80113a1f60bc8 100644
--- a/include/linux/shm.h
+++ b/include/linux/shm.h
@@ -44,6 +44,7 @@ struct shmid_ds {
#define SHM_RDONLY 010000 /* read-only access */
#define SHM_RND 020000 /* round attach address to SHMLBA boundary */
#define SHM_REMAP 040000 /* take-over region on attach */
+#define SHM_EXEC 0100000 /* execution access */
/* super user shmctl commands */
#define SHM_LOCK 11
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 2407dd8888d5d..e5f3d83ab215e 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -217,7 +217,7 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);
#ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
struct pt_regs;
-extern int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs, void *cookie);
+extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
#endif
#endif /* __KERNEL__ */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index e60ff6399a475..02da064c3dc38 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -45,6 +45,7 @@ typedef struct kmem_cache_s kmem_cache_t;
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* track pages allocated to indicate
what is reclaimable later*/
#define SLAB_PANIC 0x00040000UL /* panic if kmem_cache_create() fails */
+#define SLAB_DESTROY_BY_RCU 0x00080000UL /* defer freeing pages to RCU */
/* flags passed to a constructor func */
#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index afd89be7c193d..bec509e874de9 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -166,6 +166,7 @@ enum
VM_BLOCK_DUMP=24, /* block dump mode */
VM_HUGETLB_GROUP=25, /* permitted hugetlb group */
VM_VFS_CACHE_PRESSURE=26, /* dcache/icache reclaim pressure */
+ VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */
};
diff --git a/include/linux/time.h b/include/linux/time.h
index de41e12bbbffe..8ab20a50bd1ef 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -41,7 +41,7 @@ struct timezone {
* Have the 32 bit jiffies value wrap 5 minutes after boot
* so jiffies wrap bugs show up earlier.
*/
-#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
+#define INITIAL_JIFFIES ((unsigned long)(0))
/*
* Change timeval to jiffies, trying to avoid the
diff --git a/include/linux/wait.h b/include/linux/wait.h
index e0f2b2ffc16f0..98c8a441befaa 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -80,6 +80,15 @@ static inline int waitqueue_active(wait_queue_head_t *q)
return !list_empty(&q->task_list);
}
+/*
+ * Used to distinguish between sync and async io wait context:
+ * sync i/o typically specifies a NULL wait queue entry or a wait
+ * queue entry bound to a task (current task) to wake up.
+ * aio specifies a wait queue entry with an async notification
+ * callback routine, not associated with any task.
+ */
+#define is_sync_wait(wait) (!(wait) || ((wait)->task))
+
extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));
extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 756c2016e4a12..40c65dbb4fb17 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -428,6 +428,7 @@ u16 xfrm_flowi_sport(struct flowi *fl)
switch(fl->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_SCTP:
port = fl->fl_ip_sport;
break;
case IPPROTO_ICMP:
@@ -447,6 +448,7 @@ u16 xfrm_flowi_dport(struct flowi *fl)
switch(fl->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_SCTP:
port = fl->fl_ip_dport;
break;
case IPPROTO_ICMP:
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 4df622f6da478..79c40e218f1e6 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -103,7 +103,7 @@ typedef struct pccard_mem_map {
u_char map;
u_char flags;
u_short speed;
- u_long sys_start, sys_stop;
+ u_long static_start;
u_int card_start;
struct resource *res;
} pccard_mem_map;
diff --git a/init/Kconfig b/init/Kconfig
index 805320706a9dd..1d9857d10191a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -121,7 +121,7 @@ config BSD_PROCESS_ACCT_V3
process and it's parent. Note that this file format is incompatible
with previous v0/v1/v2 file formats, so you will need updated tools
for processing it. A preliminary version of these tools is available
- at <http://http://www.de.kernel.org/pub/linux/utils/acct/>.
+ at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>.
config SYSCTL
bool "Sysctl support"
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index 6f8900ee19b38..4abfc1c0109eb 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -122,7 +122,8 @@ identify_ramdisk_image(int fd, int start_block)
printk(KERN_NOTICE
"RAMDISK: ext2 filesystem found at block %d\n",
start_block);
- nblocks = le32_to_cpu(ext2sb->s_blocks_count);
+ nblocks = le32_to_cpu(ext2sb->s_blocks_count) <<
+ le32_to_cpu(ext2sb->s_log_block_size);
goto done;
}
@@ -173,10 +174,15 @@ int __init rd_load_image(char *from)
}
/*
- * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so
- * rd_load_image will work only with filesystem BLOCK_SIZE wide!
- * So make sure to use 1k blocksize while generating ext2fs
- * ramdisk-images.
+ * NOTE NOTE: nblocks is not actually blocks but
+ * the number of kibibytes of data to load into a ramdisk.
+ * So any ramdisk block size that is a multiple of 1KiB should
+ * work when the appropriate ramdisk_blocksize is specified
+ * on the command line.
+ *
+ * The default ramdisk_blocksize is 1KiB and it is generally
+ * silly to use anything else, so make sure to use 1KiB
+ * blocksize while generating ext2fs ramdisk-images.
*/
if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
rd_blocks = 0;
@@ -184,7 +190,7 @@ int __init rd_load_image(char *from)
rd_blocks >>= 1;
if (nblocks > rd_blocks) {
- printk("RAMDISK: image too big! (%d/%ld blocks)\n",
+ printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n",
nblocks, rd_blocks);
goto done;
}
@@ -211,7 +217,7 @@ int __init rd_load_image(char *from)
goto done;
}
- printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%ld disk%s] into ram disk... ",
+ printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ",
nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
for (i = 0, disk = 1; i < nblocks; i++) {
if (i && (i % devblocks == 0)) {
diff --git a/init/main.c b/init/main.c
index 46fe75c96308f..5f9dec5bae423 100644
--- a/init/main.c
+++ b/init/main.c
@@ -110,8 +110,8 @@ EXPORT_SYMBOL(system_state);
/*
* Boot command-line arguments
*/
-#define MAX_INIT_ARGS 8
-#define MAX_INIT_ENVS 8
+#define MAX_INIT_ARGS 32
+#define MAX_INIT_ENVS 32
extern void time_init(void);
/* Default late time init is NULL. archs can override this later. */
@@ -184,15 +184,28 @@ static int __init obsolete_checksetup(char *line)
return 0;
}
-/* this should be approx 2 Bo*oMips to start (note initial shift), and will
- still work even if initially too large, it will just take slightly longer */
+static unsigned long preset_lpj;
+static int __init lpj_setup(char *str)
+{
+ preset_lpj = simple_strtoul(str,NULL,0);
+ return 1;
+}
+
+__setup("lpj=", lpj_setup);
+
+/*
+ * This should be approx 2 Bo*oMips to start (note initial shift), and will
+ * still work even if initially too large, it will just take slightly longer
+ */
unsigned long loops_per_jiffy = (1<<12);
EXPORT_SYMBOL(loops_per_jiffy);
-/* This is the number of bits of precision for the loops_per_jiffy. Each
- bit takes on average 1.5/HZ seconds. This (like the original) is a little
- better than 1% */
+/*
+ * This is the number of bits of precision for the loops_per_jiffy. Each
+ * bit takes on average 1.5/HZ seconds. This (like the original) is a little
+ * better than 1%
+ */
#define LPS_PREC 8
void __devinit calibrate_delay(void)
@@ -200,40 +213,53 @@ void __devinit calibrate_delay(void)
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
- loops_per_jiffy = (1<<12);
-
- printk("Calibrating delay loop... ");
- while ((loops_per_jiffy <<= 1) != 0) {
- /* wait for "start of" clock tick */
- ticks = jiffies;
- while (ticks == jiffies)
- /* nothing */;
- /* Go .. */
- ticks = jiffies;
- __delay(loops_per_jiffy);
- ticks = jiffies - ticks;
- if (ticks)
- break;
- }
+ if (preset_lpj) {
+ loops_per_jiffy = preset_lpj;
+ printk("Calibrating delay loop (skipped)... "
+ "%lu.%02lu BogoMIPS preset\n",
+ loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100);
+ } else {
+ loops_per_jiffy = (1<<12);
+
+ printk(KERN_DEBUG "Calibrating delay loop... ");
+ while ((loops_per_jiffy <<= 1) != 0) {
+ /* wait for "start of" clock tick */
+ ticks = jiffies;
+ while (ticks == jiffies)
+ /* nothing */;
+ /* Go .. */
+ ticks = jiffies;
+ __delay(loops_per_jiffy);
+ ticks = jiffies - ticks;
+ if (ticks)
+ break;
+ }
+
+ /*
+ * Do a binary approximation to get loops_per_jiffy set to
+ * equal one clock (up to lps_precision bits)
+ */
+ loops_per_jiffy >>= 1;
+ loopbit = loops_per_jiffy;
+ while (lps_precision-- && (loopbit >>= 1)) {
+ loops_per_jiffy |= loopbit;
+ ticks = jiffies;
+ while (ticks == jiffies)
+ /* nothing */;
+ ticks = jiffies;
+ __delay(loops_per_jiffy);
+ if (jiffies != ticks) /* longer than 1 tick */
+ loops_per_jiffy &= ~loopbit;
+ }
-/* Do a binary approximation to get loops_per_jiffy set to equal one clock
- (up to lps_precision bits) */
- loops_per_jiffy >>= 1;
- loopbit = loops_per_jiffy;
- while ( lps_precision-- && (loopbit >>= 1) ) {
- loops_per_jiffy |= loopbit;
- ticks = jiffies;
- while (ticks == jiffies);
- ticks = jiffies;
- __delay(loops_per_jiffy);
- if (jiffies != ticks) /* longer than 1 tick */
- loops_per_jiffy &= ~loopbit;
+ /* Round the value and print it */
+ printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
+ loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100,
+ loops_per_jiffy);
}
-/* Round the value and print it */
- printk("%lu.%02lu BogoMIPS\n",
- loops_per_jiffy/(500000/HZ),
- (loops_per_jiffy/(5000/HZ)) % 100);
}
static int __init debug_kernel(char *str)
@@ -255,8 +281,10 @@ static int __init quiet_kernel(char *str)
__setup("debug", debug_kernel);
__setup("quiet", quiet_kernel);
-/* Unknown boot options get handed to init, unless they look like
- failed parameters */
+/*
+ * Unknown boot options get handed to init, unless they look like
+ * failed parameters
+ */
static int __init unknown_bootoption(char *param, char *val)
{
/* Change NUL term back to "=", to make "param" the whole string. */
@@ -267,8 +295,10 @@ static int __init unknown_bootoption(char *param, char *val)
if (obsolete_checksetup(param))
return 0;
- /* Preemptive maintenance for "why didn't my mispelled command
- line work?" */
+ /*
+ * Preemptive maintenance for "why didn't my mispelled command
+ * line work?"
+ */
if (strchr(param, '.') && (!val || strchr(param, '.') < val)) {
printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param);
return 0;
@@ -308,7 +338,8 @@ static int __init init_setup(char *str)
unsigned int i;
execute_command = str;
- /* In case LILO is going to boot us with default command line,
+ /*
+ * In case LILO is going to boot us with default command line,
* it prepends "auto" before the whole cmdline which makes
* the shell think it should execute a script with such name.
* So we ignore all arguments entered _before_ init=... [MJ]
@@ -471,7 +502,6 @@ asmlinkage void __init start_kernel(void)
* time - but meanwhile we still have a functioning scheduler.
*/
sched_init();
-
build_all_zonelists();
page_alloc_init();
printk("Kernel command line: %s\n", saved_command_line);
@@ -538,13 +568,6 @@ asmlinkage void __init start_kernel(void)
acpi_early_init(); /* before LAPIC and SMP init */
- /*
- * We count on the initial thread going ok
- * Like idlers init is an unlocked kernel thread, which will
- * make syscalls (and thus be locked).
- */
- init_idle(current, smp_processor_id());
-
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
diff --git a/ipc/shm.c b/ipc/shm.c
index 55dc1ba4229e1..530fb1f6ae1d6 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -78,7 +78,7 @@ static inline struct shmid_kernel *shm_rmid(int id)
static inline int shm_addid(struct shmid_kernel *shp)
{
- return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1);
+ return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
}
@@ -688,6 +688,10 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
o_flags = O_RDWR;
acc_mode = S_IRUGO | S_IWUGO;
}
+ if (shmflg & SHM_EXEC) {
+ prot |= PROT_EXEC;
+ acc_mode |= S_IXUGO;
+ }
/*
* We cannot rely on the fs check since SYSV IPC does have an
diff --git a/kernel/audit.c b/kernel/audit.c
index 765822b03b910..a86aaf2c8fadb 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -708,7 +708,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
audit_log_move(ab);
avail = sizeof(ab->tmp) - ab->len;
p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail);
- if (p == ERR_PTR(-ENAMETOOLONG)) {
+ if (IS_ERR(p)) {
/* FIXME: can we save some information here? */
audit_log_format(ab, "<toolong>");
} else {
diff --git a/kernel/exit.c b/kernel/exit.c
index 2b2f728220e41..b21436b147f14 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -15,6 +15,7 @@
#include <linux/tty.h>
#include <linux/namespace.h>
#include <linux/security.h>
+#include <linux/cpu.h>
#include <linux/acct.h>
#include <linux/file.h>
#include <linux/binfmts.h>
@@ -56,8 +57,6 @@ void release_task(struct task_struct * p)
struct dentry *proc_dentry;
repeat:
- BUG_ON(p->state < TASK_ZOMBIE);
-
atomic_dec(&p->user->processes);
spin_lock(&p->proc_lock);
proc_dentry = proc_pid_unhash(p);
@@ -755,9 +754,8 @@ static void exit_notify(struct task_struct *tsk)
state = TASK_ZOMBIE;
if (tsk->exit_signal == -1 && tsk->ptrace == 0)
state = TASK_DEAD;
- tsk->state = state;
- tsk->flags |= PF_DEAD;
-
+ else
+ tsk->state = state;
/*
* Clear these here so that update_process_times() won't try to deliver
* itimer, profile or rlimit signals to this task while it is in late exit.
@@ -767,19 +765,14 @@ static void exit_notify(struct task_struct *tsk)
tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY;
/*
- * In the preemption case it must be impossible for the task
- * to get runnable again, so use "_raw_" unlock to keep
- * preempt_count elevated until we schedule().
- *
- * To avoid deadlock on SMP, interrupts must be unmasked. If we
- * don't, subsequently called functions (e.g, wait_task_inactive()
- * via release_task()) will spin, with interrupt flags
- * unwittingly blocked, until the other task sleeps. That task
- * may itself be waiting for smp_call_function() to answer and
- * complete, and with interrupts blocked that will never happen.
+ * Get a reference to it so that we can set the state
+ * as the last step. The state-setting only matters if the
+ * current task is releasing itself, to trigger the final
+ * put_task_struct() in finish_task_switch(). (thread self-reap)
*/
- _raw_write_unlock(&tasklist_lock);
- local_irq_enable();
+ get_task_struct(tsk);
+
+ write_unlock_irq(&tasklist_lock);
list_for_each_safe(_p, _n, &ptrace_dead) {
list_del_init(_p);
@@ -788,9 +781,23 @@ static void exit_notify(struct task_struct *tsk)
}
/* If the process is dead, release it - nobody will wait for it */
- if (state == TASK_DEAD)
+ if (state == TASK_DEAD) {
+ lock_cpu_hotplug();
release_task(tsk);
+ write_lock_irq(&tasklist_lock);
+ /*
+ * No preemption may happen from this point on,
+ * or CPU hotplug (and task exit) breaks:
+ */
+ unlock_cpu_hotplug();
+ tsk->state = state;
+ _raw_write_unlock(&tasklist_lock);
+ local_irq_enable();
+ } else
+ preempt_disable();
+ tsk->flags |= PF_DEAD;
+ put_task_struct(tsk);
}
asmlinkage NORET_TYPE void do_exit(long code)
diff --git a/kernel/fork.c b/kernel/fork.c
index 601abf6bbbb80..cc0aa2726a841 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -152,7 +152,12 @@ void fastcall prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int stat
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list))
__add_wait_queue(q, wait);
- set_current_state(state);
+ /*
+ * don't alter the task state if this is just going to
+ * queue an async wait queue callback
+ */
+ if (is_sync_wait(wait))
+ set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
}
@@ -167,7 +172,12 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list))
__add_wait_queue_tail(q, wait);
- set_current_state(state);
+ /*
+ * don't alter the task state if this is just going to
+ * queue an async wait queue callback
+ */
+ if (is_sync_wait(wait))
+ set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
}
@@ -280,7 +290,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm)
mm->locked_vm = 0;
mm->mmap = NULL;
mm->mmap_cache = NULL;
- mm->free_area_cache = TASK_UNMAPPED_BASE;
+ mm->free_area_cache = oldmm->mmap_base;
mm->map_count = 0;
mm->rss = 0;
cpus_clear(mm->cpu_vm_mask);
@@ -467,20 +477,34 @@ void mmput(struct mm_struct *mm)
}
}
-/*
- * Checks if the use count of an mm is non-zero and if so
- * returns a reference to it after bumping up the use count.
- * If the use count is zero, it means this mm is going away,
- * so return NULL.
+/**
+ * get_task_mm - acquire a reference to the task's mm
+ *
+ * Returns %NULL if the task has no mm. Checks if the use count
+ * of the mm is non-zero and if so returns a reference to it, after
+ * bumping up the use count. User must release the mm via mmput()
+ * after use. Typically used by /proc and ptrace.
+ *
+ * If the use count is zero, it means that this mm is going away,
+ * so return %NULL. This only happens in the case of an AIO daemon
+ * which has temporarily adopted an mm (see use_mm), in the course
+ * of its final mmput, before exit_aio has completed.
*/
-struct mm_struct *mmgrab(struct mm_struct *mm)
+struct mm_struct *get_task_mm(struct task_struct *task)
{
- spin_lock(&mmlist_lock);
- if (!atomic_read(&mm->mm_users))
- mm = NULL;
- else
- atomic_inc(&mm->mm_users);
- spin_unlock(&mmlist_lock);
+ struct mm_struct *mm;
+
+ task_lock(task);
+ mm = task->mm;
+ if (mm) {
+ spin_lock(&mmlist_lock);
+ if (!atomic_read(&mm->mm_users))
+ mm = NULL;
+ else
+ atomic_inc(&mm->mm_users);
+ spin_unlock(&mmlist_lock);
+ }
+ task_unlock(task);
return mm;
}
@@ -865,12 +889,13 @@ asmlinkage long sys_set_tid_address(int __user *tidptr)
* parts of the process environment (as per the clone
* flags). The actual kick-off is left to the caller.
*/
-struct task_struct *copy_process(unsigned long clone_flags,
+static task_t *copy_process(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
- int __user *child_tidptr)
+ int __user *child_tidptr,
+ int pid)
{
int retval;
struct task_struct *p = NULL;
@@ -930,13 +955,7 @@ struct task_struct *copy_process(unsigned long clone_flags,
p->did_exec = 0;
copy_flags(clone_flags, p);
- if (clone_flags & CLONE_IDLETASK)
- p->pid = 0;
- else {
- p->pid = alloc_pidmap();
- if (p->pid == -1)
- goto bad_fork_cleanup;
- }
+ p->pid = pid;
retval = -EFAULT;
if (clone_flags & CLONE_PARENT_SETTID)
if (put_user(p->pid, parent_tidptr))
@@ -965,6 +984,7 @@ struct task_struct *copy_process(unsigned long clone_flags,
p->start_time = get_jiffies_64();
p->security = NULL;
p->io_context = NULL;
+ p->io_wait = NULL;
p->audit_context = NULL;
#ifdef CONFIG_NUMA
p->mempolicy = mpol_copy(p->mempolicy);
@@ -1033,6 +1053,17 @@ struct task_struct *copy_process(unsigned long 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.
+ */
+ p->cpus_allowed = current->cpus_allowed;
+ set_task_cpu(p, smp_processor_id());
+
/*
* Check for pending SIGKILL! The new thread should not be allowed
* to slip out of an OOM kill. (or normal SIGKILL.)
@@ -1127,8 +1158,6 @@ bad_fork_cleanup_policy:
mpol_free(p->mempolicy);
#endif
bad_fork_cleanup:
- if (p->pid > 0)
- free_pidmap(p->pid);
if (p->binfmt)
module_put(p->binfmt->module);
bad_fork_cleanup_put_domain:
@@ -1142,9 +1171,28 @@ bad_fork_free:
goto fork_out;
}
+struct pt_regs * __init __attribute__((weak)) idle_regs(struct pt_regs *regs)
+{
+ memset(regs, 0, sizeof(struct pt_regs));
+ return regs;
+}
+
+task_t * __init fork_idle(int cpu)
+{
+ task_t *task;
+ struct pt_regs regs;
+
+ task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL, 0);
+ if (!task)
+ return ERR_PTR(-ENOMEM);
+ init_idle(task, cpu);
+ unhash_process(task);
+ return task;
+}
+
static inline int fork_traceflag (unsigned clone_flags)
{
- if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK))
+ if (clone_flags & CLONE_UNTRACED)
return 0;
else if (clone_flags & CLONE_VFORK) {
if (current->ptrace & PT_TRACE_VFORK)
@@ -1173,21 +1221,21 @@ long do_fork(unsigned long clone_flags,
{
struct task_struct *p;
int trace = 0;
- long pid;
+ long pid = alloc_pidmap();
+ if (pid < 0)
+ return -EAGAIN;
if (unlikely(current->ptrace)) {
trace = fork_traceflag (clone_flags);
if (trace)
clone_flags |= CLONE_PTRACE;
}
- p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr);
+ p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
*/
- pid = IS_ERR(p) ? PTR_ERR(p) : p->pid;
-
if (!IS_ERR(p)) {
struct completion vfork;
@@ -1204,31 +1252,10 @@ long do_fork(unsigned long clone_flags,
set_tsk_thread_flag(p, TIF_SIGPENDING);
}
- if (!(clone_flags & CLONE_STOPPED)) {
- /*
- * Do the wakeup last. On SMP we treat fork() and
- * CLONE_VM separately, because fork() has already
- * created cache footprint on this CPU (due to
- * copying the pagetables), hence migration would
- * probably be costy. Threads on the other hand
- * have less traction to the current CPU, and if
- * there's an imbalance then the scheduler can
- * migrate this fresh thread now, before it
- * accumulates a larger cache footprint:
- */
- if (clone_flags & CLONE_VM)
- wake_up_forked_thread(p);
- else
- wake_up_forked_process(p);
- } else {
- int cpu = get_cpu();
-
+ if (!(clone_flags & CLONE_STOPPED))
+ wake_up_new_task(p, clone_flags);
+ else
p->state = TASK_STOPPED;
- if (cpu_is_offline(task_cpu(p)))
- set_task_cpu(p, cpu);
-
- put_cpu();
- }
++total_forks;
if (unlikely (trace)) {
@@ -1240,12 +1267,10 @@ long do_fork(unsigned long clone_flags,
wait_for_completion(&vfork);
if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
- } else
- /*
- * Let the child process run first, to avoid most of the
- * COW overhead when the child exec()s afterwards.
- */
- set_need_resched();
+ }
+ } else {
+ free_pidmap(pid);
+ pid = PTR_ERR(p);
}
return pid;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 2d4d157bc145c..0b415e7b429df 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -40,6 +40,8 @@
#include <linux/cpu.h>
#include <linux/percpu.h>
#include <linux/kthread.h>
+#include <linux/seq_file.h>
+#include <linux/times.h>
#include <asm/tlb.h>
#include <asm/unistd.h>
@@ -67,8 +69,6 @@
#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
-#define AVG_TIMESLICE (MIN_TIMESLICE + ((MAX_TIMESLICE - MIN_TIMESLICE) *\
- (MAX_PRIO-1-NICE_TO_PRIO(0))/(MAX_USER_PRIO - 1)))
/*
* Some helpers for converting nanosecond timing to jiffy resolution
@@ -79,12 +79,12 @@
/*
* These are the 'tuning knobs' of the scheduler:
*
- * Minimum timeslice is 10 msecs, default timeslice is 100 msecs,
- * maximum timeslice is 200 msecs. Timeslices get refilled after
- * they expire.
+ * Minimum timeslice is 5 msecs (or 1 jiffy, whichever is larger),
+ * default timeslice is 100 msecs, maximum timeslice is 800 msecs.
+ * Timeslices get refilled after they expire.
*/
-#define MIN_TIMESLICE ( 10 * HZ / 1000)
-#define MAX_TIMESLICE (200 * HZ / 1000)
+#define MIN_TIMESLICE max(5 * HZ / 1000, 1)
+#define DEF_TIMESLICE (100 * HZ / 1000)
#define ON_RUNQUEUE_WEIGHT 30
#define CHILD_PENALTY 95
#define PARENT_PENALTY 100
@@ -92,7 +92,7 @@
#define PRIO_BONUS_RATIO 25
#define MAX_BONUS (MAX_USER_PRIO * PRIO_BONUS_RATIO / 100)
#define INTERACTIVE_DELTA 2
-#define MAX_SLEEP_AVG (AVG_TIMESLICE * MAX_BONUS)
+#define MAX_SLEEP_AVG (DEF_TIMESLICE * MAX_BONUS)
#define STARVATION_LIMIT (MAX_SLEEP_AVG)
#define NS_MAX_SLEEP_AVG (JIFFIES_TO_NS(MAX_SLEEP_AVG))
#define CREDIT_LIMIT 100
@@ -161,27 +161,36 @@
((p)->prio < (rq)->curr->prio)
/*
- * BASE_TIMESLICE scales user-nice values [ -20 ... 19 ]
- * to time slice values.
+ * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
+ * to time slice values: [800ms ... 100ms ... 5ms]
*
* The higher a thread's priority, the bigger timeslices
* it gets during one round of execution. But even the lowest
* priority thread gets MIN_TIMESLICE worth of execution time.
- *
- * task_timeslice() is the interface that is used by the scheduler.
*/
-#define BASE_TIMESLICE(p) (MIN_TIMESLICE + \
- ((MAX_TIMESLICE - MIN_TIMESLICE) * \
- (MAX_PRIO-1 - (p)->static_prio) / (MAX_USER_PRIO-1)))
+#define SCALE_PRIO(x, prio) \
+ max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)
static unsigned int task_timeslice(task_t *p)
{
- return BASE_TIMESLICE(p);
+ if (p->static_prio < NICE_TO_PRIO(0))
+ return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
+ else
+ return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);
}
-
#define task_hot(p, now, sd) ((now) - (p)->timestamp < (sd)->cache_hot_time)
+enum idle_type
+{
+ IDLE,
+ NOT_IDLE,
+ NEWLY_IDLE,
+ MAX_IDLE_TYPES
+};
+
+struct sched_domain;
+
/*
* These are the runqueue data structures:
*/
@@ -233,10 +242,186 @@ struct runqueue {
task_t *migration_thread;
struct list_head migration_queue;
#endif
+
+#ifdef CONFIG_SCHEDSTATS
+ /* latency stats */
+ struct sched_info rq_sched_info;
+
+ /* sys_sched_yield() stats */
+ unsigned long yld_exp_empty;
+ unsigned long yld_act_empty;
+ unsigned long yld_both_empty;
+ unsigned long yld_cnt;
+
+ /* schedule() stats */
+ unsigned long sched_noswitch;
+ unsigned long sched_switch;
+ unsigned long sched_cnt;
+ unsigned long sched_goidle;
+
+ /* pull_task() stats */
+ unsigned long pt_gained[MAX_IDLE_TYPES];
+ unsigned long pt_lost[MAX_IDLE_TYPES];
+
+ /* active_load_balance() stats */
+ unsigned long alb_cnt;
+ unsigned long alb_lost;
+ unsigned long alb_gained;
+ unsigned long alb_failed;
+
+ /* try_to_wake_up() stats */
+ unsigned long ttwu_cnt;
+ unsigned long ttwu_attempts;
+ unsigned long ttwu_moved;
+
+ /* wake_up_new_task() stats */
+ unsigned long wunt_cnt;
+ unsigned long wunt_moved;
+
+ /* sched_migrate_task() stats */
+ unsigned long smt_cnt;
+
+ /* sched_balance_exec() stats */
+ unsigned long sbe_cnt;
+#endif
};
static DEFINE_PER_CPU(struct runqueue, runqueues);
+/*
+ * sched-domains (multiprocessor balancing) declarations:
+ */
+#ifdef CONFIG_SMP
+#define SCHED_LOAD_SCALE 128UL /* increase resolution of load */
+
+#define SD_BALANCE_NEWIDLE 1 /* Balance when about to become idle */
+#define SD_BALANCE_EXEC 2 /* Balance on exec */
+#define SD_WAKE_IDLE 4 /* Wake to idle CPU on task wakeup */
+#define SD_WAKE_AFFINE 8 /* Wake task to waking CPU */
+#define SD_WAKE_BALANCE 16 /* Perform balancing at task wakeup */
+#define SD_SHARE_CPUPOWER 32 /* Domain members share cpu power */
+
+struct sched_group {
+ struct sched_group *next; /* Must be a circular list */
+ cpumask_t cpumask;
+
+ /*
+ * CPU power of this group, SCHED_LOAD_SCALE being max power for a
+ * single CPU. This should be read only (except for setup). Although
+ * it will need to be written to at cpu hot(un)plug time, perhaps the
+ * cpucontrol semaphore will provide enough exclusion?
+ */
+ unsigned long cpu_power;
+};
+
+struct sched_domain {
+ /* These fields must be setup */
+ struct sched_domain *parent; /* top domain must be null terminated */
+ struct sched_group *groups; /* the balancing groups of the domain */
+ cpumask_t span; /* span of all CPUs in this domain */
+ unsigned long min_interval; /* Minimum balance interval ms */
+ unsigned long max_interval; /* Maximum balance interval ms */
+ unsigned int busy_factor; /* less balancing by factor if busy */
+ unsigned int imbalance_pct; /* No balance until over watermark */
+ 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 */
+ int flags; /* See SD_* */
+
+ /* Runtime fields. */
+ unsigned long last_balance; /* init to jiffies. units in jiffies */
+ unsigned int balance_interval; /* initialise to 1. units in ms. */
+ unsigned int nr_balance_failed; /* initialise to 0 */
+
+#ifdef CONFIG_SCHEDSTATS
+ /* load_balance() stats */
+ unsigned long lb_cnt[MAX_IDLE_TYPES];
+ unsigned long lb_failed[MAX_IDLE_TYPES];
+ unsigned long lb_imbalance[MAX_IDLE_TYPES];
+ unsigned long lb_nobusyg[MAX_IDLE_TYPES];
+ unsigned long lb_nobusyq[MAX_IDLE_TYPES];
+
+ /* sched_balance_exec() stats */
+ unsigned long sbe_attempts;
+ unsigned long sbe_pushed;
+
+ /* try_to_wake_up() stats */
+ unsigned long ttwu_wake_affine;
+ unsigned long ttwu_wake_balance;
+#endif
+};
+
+#ifndef ARCH_HAS_SCHED_TUNE
+#ifdef CONFIG_SCHED_SMT
+#define ARCH_HAS_SCHED_WAKE_IDLE
+/* Common values for SMT siblings */
+#define SD_SIBLING_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .groups = NULL, \
+ .min_interval = 1, \
+ .max_interval = 2, \
+ .busy_factor = 8, \
+ .imbalance_pct = 110, \
+ .cache_hot_time = 0, \
+ .cache_nice_tries = 0, \
+ .per_cpu_gain = 25, \
+ .flags = SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_EXEC \
+ | SD_WAKE_AFFINE \
+ | SD_WAKE_IDLE \
+ | SD_SHARE_CPUPOWER, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+}
+#endif
+
+/* Common values for CPUs */
+#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 = (5*1000000/2), \
+ .cache_nice_tries = 1, \
+ .per_cpu_gain = 100, \
+ .flags = SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_EXEC \
+ | SD_WAKE_AFFINE \
+ | SD_WAKE_BALANCE, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+}
+
+/* Arch can override this macro in processor.h */
+#if defined(CONFIG_NUMA) && !defined(SD_NODE_INIT)
+#define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 32, \
+ .busy_factor = 32, \
+ .imbalance_pct = 125, \
+ .cache_hot_time = (10*1000000), \
+ .cache_nice_tries = 1, \
+ .per_cpu_gain = 100, \
+ .flags = SD_BALANCE_EXEC \
+ | SD_WAKE_BALANCE, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+}
+#endif
+#endif /* ARCH_HAS_SCHED_TUNE */
+#endif
+
+
#define for_each_domain(cpu, domain) \
for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent)
@@ -279,6 +464,104 @@ static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags)
spin_unlock_irqrestore(&rq->lock, *flags);
}
+#ifdef CONFIG_SCHEDSTATS
+/*
+ * 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 10
+
+static int show_schedstat(struct seq_file *seq, void *v)
+{
+ int cpu;
+ enum idle_type itype;
+
+ seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
+ seq_printf(seq, "timestamp %lu\n", jiffies);
+ for_each_online_cpu(cpu) {
+ runqueue_t *rq = cpu_rq(cpu);
+#ifdef CONFIG_SMP
+ struct sched_domain *sd;
+ int dcnt = 0;
+#endif
+
+ /* runqueue-specific stats */
+ seq_printf(seq,
+ "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
+ "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ cpu, rq->yld_both_empty,
+ rq->yld_act_empty, rq->yld_exp_empty,
+ rq->yld_cnt, rq->sched_noswitch,
+ rq->sched_switch, rq->sched_cnt, rq->sched_goidle,
+ rq->alb_cnt, rq->alb_gained, rq->alb_lost,
+ rq->alb_failed,
+ rq->ttwu_cnt, rq->ttwu_moved, rq->ttwu_attempts,
+ rq->wunt_cnt, rq->wunt_moved,
+ rq->smt_cnt, rq->sbe_cnt, rq->rq_sched_info.cpu_time,
+ rq->rq_sched_info.run_delay, rq->rq_sched_info.pcnt);
+
+ for (itype = IDLE; itype < MAX_IDLE_TYPES; itype++)
+ seq_printf(seq, " %lu %lu", rq->pt_gained[itype],
+ rq->pt_lost[itype]);
+ seq_printf(seq, "\n");
+
+#ifdef CONFIG_SMP
+ /* domain-specific stats */
+ for_each_domain(cpu, sd) {
+ char mask_str[NR_CPUS];
+
+ cpumask_scnprintf(mask_str, NR_CPUS, sd->span);
+ seq_printf(seq, "domain%d %s", dcnt++, mask_str);
+ for (itype = IDLE; itype < MAX_IDLE_TYPES; itype++) {
+ seq_printf(seq, " %lu %lu %lu %lu %lu",
+ sd->lb_cnt[itype],
+ sd->lb_failed[itype],
+ sd->lb_imbalance[itype],
+ sd->lb_nobusyq[itype],
+ sd->lb_nobusyg[itype]);
+ }
+ seq_printf(seq, " %lu %lu %lu %lu\n",
+ sd->sbe_pushed, sd->sbe_attempts,
+ sd->ttwu_wake_affine, sd->ttwu_wake_balance);
+ }
+#endif
+ }
+ return 0;
+}
+
+static int schedstat_open(struct inode *inode, struct file *file)
+{
+ unsigned int size = PAGE_SIZE * (1 + num_online_cpus() / 32);
+ char *buf = kmalloc(size, GFP_KERNEL);
+ struct seq_file *m;
+ int res;
+
+ if (!buf)
+ return -ENOMEM;
+ res = single_open(file, show_schedstat, NULL);
+ if (!res) {
+ m = file->private_data;
+ m->buf = buf;
+ m->size = size;
+ } else
+ kfree(buf);
+ return res;
+}
+
+struct file_operations proc_schedstat_operations = {
+ .open = schedstat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+# define schedstat_inc(rq, field) rq->field++;
+# define schedstat_add(rq, field, amt) rq->field += amt;
+#else /* !CONFIG_SCHEDSTATS */
+# define schedstat_inc(rq, field) do { } while (0);
+# define schedstat_add(rq, field, amt) do { } while (0);
+#endif
+
/*
* rq_lock - lock a given runqueue and disable interrupts.
*/
@@ -298,6 +581,112 @@ static inline void rq_unlock(runqueue_t *rq)
spin_unlock_irq(&rq->lock);
}
+#ifdef CONFIG_SCHEDSTATS
+/*
+ * Called when a process is dequeued from the active array and given
+ * the cpu. We should note that with the exception of interactive
+ * tasks, the expired queue will become the active queue after the active
+ * queue is empty, without explicitly dequeuing and requeuing tasks in the
+ * expired queue. (Interactive tasks may be requeued directly to the
+ * active queue, thus delaying tasks in the expired queue from running;
+ * see scheduler_tick()).
+ *
+ * This function is only called from sched_info_arrive(), rather than
+ * dequeue_task(). Even though a task may be queued and dequeued multiple
+ * times as it is shuffled about, we're really interested in knowing how
+ * long it was from the *first* time it was queued to the time that it
+ * finally hit a cpu.
+ */
+static inline void sched_info_dequeued(task_t *t)
+{
+ t->sched_info.last_queued = 0;
+}
+
+/*
+ * Called when a task finally hits the cpu. We can now calculate how
+ * long it was waiting to run. We also note when it began so that we
+ * can keep stats on how long its timeslice is.
+ */
+static inline void sched_info_arrive(task_t *t)
+{
+ unsigned long now = jiffies, diff = 0;
+ struct runqueue *rq = task_rq(t);
+
+ if (t->sched_info.last_queued)
+ diff = now - t->sched_info.last_queued;
+ sched_info_dequeued(t);
+ t->sched_info.run_delay += diff;
+ t->sched_info.last_arrival = now;
+ t->sched_info.pcnt++;
+
+ if (!rq)
+ return;
+
+ rq->rq_sched_info.run_delay += diff;
+ rq->rq_sched_info.pcnt++;
+}
+
+/*
+ * Called when a process is queued into either the active or expired
+ * array. The time is noted and later used to determine how long we
+ * had to wait for us to reach the cpu. Since the expired queue will
+ * become the active queue after active queue is empty, without dequeuing
+ * and requeuing any tasks, we are interested in queuing to either. It
+ * is unusual but not impossible for tasks to be dequeued and immediately
+ * requeued in the same or another array: this can happen in sched_yield(),
+ * set_user_nice(), and even load_balance() as it moves tasks from runqueue
+ * to runqueue.
+ *
+ * This function is only called from enqueue_task(), but also only updates
+ * the timestamp if it is already not set. It's assumed that
+ * sched_info_dequeued() will clear that stamp when appropriate.
+ */
+static inline void sched_info_queued(task_t *t)
+{
+ if (!t->sched_info.last_queued)
+ t->sched_info.last_queued = jiffies;
+}
+
+/*
+ * Called when a process ceases being the active-running process, either
+ * voluntarily or involuntarily. Now we can calculate how long we ran.
+ */
+static inline void sched_info_depart(task_t *t)
+{
+ struct runqueue *rq = task_rq(t);
+ unsigned long diff = jiffies - t->sched_info.last_arrival;
+
+ t->sched_info.cpu_time += diff;
+
+ if (rq)
+ rq->rq_sched_info.cpu_time += diff;
+}
+
+/*
+ * Called when tasks are switched involuntarily due, typically, to expiring
+ * their time slice. (This may also be called when switching to or from
+ * the idle task.) We are only called when prev != next.
+ */
+static inline void sched_info_switch(task_t *prev, task_t *next)
+{
+ struct runqueue *rq = task_rq(prev);
+
+ /*
+ * prev now departs the cpu. It's not interesting to record
+ * stats about how efficient we were at scheduling the idle
+ * process, however.
+ */
+ if (prev != rq->idle)
+ sched_info_depart(prev);
+
+ if (next != rq->idle)
+ sched_info_arrive(next);
+}
+#else
+#define sched_info_queued(t) do { } while (0)
+#define sched_info_switch(t, next) do { } while (0)
+#endif /* CONFIG_SCHEDSTATS */
+
/*
* Adding/removing a task to/from a priority array:
*/
@@ -311,6 +700,7 @@ static void dequeue_task(struct task_struct *p, prio_array_t *array)
static void enqueue_task(struct task_struct *p, prio_array_t *array)
{
+ sched_info_queued(p);
list_add_tail(&p->run_list, array->queue + p->prio);
__set_bit(p->prio, array->bitmap);
array->nr_active++;
@@ -399,7 +789,7 @@ static void recalc_task_prio(task_t *p, unsigned long long now)
if (p->mm && p->activated != -1 &&
sleep_time > INTERACTIVE_SLEEP(p)) {
p->sleep_avg = JIFFIES_TO_NS(MAX_SLEEP_AVG -
- AVG_TIMESLICE);
+ DEF_TIMESLICE);
if (!HIGH_CREDIT(p))
p->interactive_credit++;
} else {
@@ -526,7 +916,8 @@ static void resched_task(task_t *p)
{
int need_resched, nrpolling;
- preempt_disable();
+ BUG_ON(!spin_is_locked(&task_rq(p)->lock));
+
/* minimise the chance of sending an interrupt to poll_idle() */
nrpolling = test_tsk_thread_flag(p,TIF_POLLING_NRFLAG);
need_resched = test_and_set_tsk_thread_flag(p,TIF_NEED_RESCHED);
@@ -534,7 +925,6 @@ static void resched_task(task_t *p)
if (!need_resched && !nrpolling && (task_cpu(p) != smp_processor_id()))
smp_send_reschedule(task_cpu(p));
- preempt_enable();
}
#else
static inline void resched_task(task_t *p)
@@ -740,6 +1130,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
#endif
rq = task_rq_lock(p, &flags);
+ schedstat_inc(rq, ttwu_cnt);
old_state = p->state;
if (!(old_state & state))
goto out;
@@ -787,23 +1178,35 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
*/
imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2;
- if ( ((sd->flags & SD_WAKE_AFFINE) &&
- !task_hot(p, rq->timestamp_last_tick, sd))
- || ((sd->flags & SD_WAKE_BALANCE) &&
- imbalance*this_load <= 100*load) ) {
+ if ((sd->flags & SD_WAKE_AFFINE) &&
+ !task_hot(p, rq->timestamp_last_tick, sd)) {
+ /*
+ * This domain has SD_WAKE_AFFINE and p is cache cold
+ * in this domain.
+ */
+ if (cpu_isset(cpu, sd->span)) {
+ schedstat_inc(sd, ttwu_wake_affine);
+ goto out_set_cpu;
+ }
+ } else if ((sd->flags & SD_WAKE_BALANCE) &&
+ imbalance*this_load <= 100*load) {
/*
- * Now sd has SD_WAKE_AFFINE and p is cache cold in sd
- * or sd has SD_WAKE_BALANCE and there is an imbalance
+ * This domain has SD_WAKE_BALANCE and there is
+ * an imbalance.
*/
- if (cpu_isset(cpu, sd->span))
+ if (cpu_isset(cpu, sd->span)) {
+ schedstat_inc(sd, ttwu_wake_balance);
goto out_set_cpu;
+ }
}
}
new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */
out_set_cpu:
+ schedstat_inc(rq, ttwu_attempts);
new_cpu = wake_idle(new_cpu, p);
if (new_cpu != cpu && cpu_isset(new_cpu, p->cpus_allowed)) {
+ schedstat_inc(rq, ttwu_moved);
set_task_cpu(p, new_cpu);
task_rq_unlock(rq, &flags);
/* might preempt at this point */
@@ -865,6 +1268,11 @@ 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.
@@ -881,6 +1289,9 @@ void fastcall sched_fork(task_t *p)
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
#ifdef CONFIG_PREEMPT
/*
* During context-switch we hold precisely one spinlock, which
@@ -904,7 +1315,7 @@ void fastcall sched_fork(task_t *p)
p->first_time_slice = 1;
current->time_slice >>= 1;
p->timestamp = sched_clock();
- if (!current->time_slice) {
+ if (unlikely(!current->time_slice)) {
/*
* This case is rare, it happens when the parent has only
* a single jiffy left from its timeslice. Taking the
@@ -920,44 +1331,89 @@ void fastcall sched_fork(task_t *p)
}
/*
- * wake_up_forked_process - wake up a freshly forked process.
+ * wake_up_new_task - wake up a newly created task for the first time.
*
* This function will do some initial scheduler statistics housekeeping
- * that must be done for every newly created process.
+ * that must be done for every newly created context, then puts the task
+ * on the runqueue and wakes it.
*/
-void fastcall wake_up_forked_process(task_t * p)
+void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags)
{
unsigned long flags;
- runqueue_t *rq = task_rq_lock(current, &flags);
+ int this_cpu, cpu;
+ 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);
+ schedstat_inc(rq, wunt_cnt);
/*
* We decrease the sleep average of forking parents
* and children as well, to keep max-interactive tasks
- * from forking tasks that are max-interactive.
+ * from forking tasks that are max-interactive. The parent
+ * (current) is done further down, under its lock.
*/
- current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
- PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
-
p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) *
CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
p->interactive_credit = 0;
p->prio = effective_prio(p);
- set_task_cpu(p, smp_processor_id());
- if (unlikely(!current->array))
+ if (likely(cpu == this_cpu)) {
+ if (!(clone_flags & CLONE_VM)) {
+ /*
+ * The VM isn't cloned, so we're in a good position to
+ * do child-runs-first in anticipation of an exec. This
+ * usually avoids a lot of COW overhead.
+ */
+ if (unlikely(!current->array))
+ __activate_task(p, rq);
+ else {
+ p->prio = current->prio;
+ list_add_tail(&p->run_list, &current->run_list);
+ p->array = current->array;
+ p->array->nr_active++;
+ rq->nr_running++;
+ }
+ set_need_resched();
+ } else
+ /* Run child last */
+ __activate_task(p, rq);
+ /*
+ * We skip the following code due to cpu == this_cpu
+ *
+ * task_rq_unlock(rq, &flags);
+ * this_rq = task_rq_lock(current, &flags);
+ */
+ this_rq = rq;
+ } else {
+ this_rq = cpu_rq(this_cpu);
+
+ /*
+ * Not the local CPU - must adjust timestamp. This should
+ * get optimised away in the !CONFIG_SMP case.
+ */
+ p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
+ + rq->timestamp_last_tick;
__activate_task(p, rq);
- else {
- p->prio = current->prio;
- list_add_tail(&p->run_list, &current->run_list);
- p->array = current->array;
- p->array->nr_active++;
- rq->nr_running++;
+ if (TASK_PREEMPTS_CURR(p, rq))
+ resched_task(rq->curr);
+
+ schedstat_inc(rq, wunt_moved);
+ /*
+ * Parent and child are on different CPUs, now get the
+ * parent runqueue to update the parent's ->sleep_avg:
+ */
+ task_rq_unlock(rq, &flags);
+ this_rq = task_rq_lock(current, &flags);
}
- task_rq_unlock(rq, &flags);
+ current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
+ PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
+ task_rq_unlock(this_rq, &flags);
}
/*
@@ -974,18 +1430,16 @@ void fastcall sched_exit(task_t * p)
unsigned long flags;
runqueue_t *rq;
- local_irq_save(flags);
- if (p->first_time_slice) {
- p->parent->time_slice += p->time_slice;
- if (unlikely(p->parent->time_slice > MAX_TIMESLICE))
- p->parent->time_slice = MAX_TIMESLICE;
- }
- local_irq_restore(flags);
/*
* If the child was a (relative-) CPU hog then decrease
* the sleep_avg of the parent as well.
*/
rq = task_rq_lock(p->parent, &flags);
+ if (p->first_time_slice) {
+ p->parent->time_slice += p->time_slice;
+ if (unlikely(p->parent->time_slice > task_timeslice(p)))
+ p->parent->time_slice = task_timeslice(p);
+ }
if (p->sleep_avg < p->parent->sleep_avg)
p->parent->sleep_avg = p->parent->sleep_avg /
(EXIT_WEIGHT + 1) * EXIT_WEIGHT + p->sleep_avg /
@@ -1085,7 +1539,7 @@ unsigned long nr_running(void)
{
unsigned long i, sum = 0;
- for_each_cpu(i)
+ for_each_online_cpu(i)
sum += cpu_rq(i)->nr_running;
return sum;
@@ -1121,6 +1575,8 @@ unsigned long nr_iowait(void)
return sum;
}
+#ifdef CONFIG_SMP
+
/*
* double_rq_lock - safely lock two runqueues
*
@@ -1155,14 +1611,20 @@ static void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2)
spin_unlock(&rq2->lock);
}
-enum idle_type
+/*
+ * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
+ */
+static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
{
- IDLE,
- NOT_IDLE,
- NEWLY_IDLE,
-};
-
-#ifdef CONFIG_SMP
+ if (unlikely(!spin_trylock(&busiest->lock))) {
+ if (busiest < this_rq) {
+ spin_unlock(&this_rq->lock);
+ spin_lock(&busiest->lock);
+ spin_lock(&this_rq->lock);
+ } else
+ spin_lock(&busiest->lock);
+ }
+}
/*
* find_idlest_cpu - find the least busy runqueue.
@@ -1211,89 +1673,6 @@ static int find_idlest_cpu(struct task_struct *p, int this_cpu,
}
/*
- * wake_up_forked_thread - wake up a freshly forked thread.
- *
- * This function will do some initial scheduler statistics housekeeping
- * that must be done for every newly created context, and it also does
- * runqueue balancing.
- */
-void fastcall wake_up_forked_thread(task_t * p)
-{
- unsigned long flags;
- int this_cpu = get_cpu(), cpu;
- struct sched_domain *tmp, *sd = NULL;
- runqueue_t *this_rq = cpu_rq(this_cpu), *rq;
-
- /*
- * Find the largest domain that this CPU is part of that
- * is willing to balance on clone:
- */
- for_each_domain(this_cpu, tmp)
- if (tmp->flags & SD_BALANCE_CLONE)
- sd = tmp;
- if (sd)
- cpu = find_idlest_cpu(p, this_cpu, sd);
- else
- cpu = this_cpu;
-
- local_irq_save(flags);
-lock_again:
- rq = cpu_rq(cpu);
- double_rq_lock(this_rq, rq);
-
- BUG_ON(p->state != TASK_RUNNING);
-
- /*
- * We did find_idlest_cpu() unlocked, so in theory
- * the mask could have changed - just dont migrate
- * in this case:
- */
- if (unlikely(!cpu_isset(cpu, p->cpus_allowed))) {
- cpu = this_cpu;
- double_rq_unlock(this_rq, rq);
- goto lock_again;
- }
- /*
- * We decrease the sleep average of forking parents
- * and children as well, to keep max-interactive tasks
- * from forking tasks that are max-interactive.
- */
- current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
- PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
-
- p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) *
- CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
-
- p->interactive_credit = 0;
-
- p->prio = effective_prio(p);
- set_task_cpu(p, cpu);
-
- if (cpu == this_cpu) {
- if (unlikely(!current->array))
- __activate_task(p, rq);
- else {
- p->prio = current->prio;
- list_add_tail(&p->run_list, &current->run_list);
- p->array = current->array;
- p->array->nr_active++;
- rq->nr_running++;
- }
- } else {
- /* Not the local CPU - must adjust timestamp */
- p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
- + rq->timestamp_last_tick;
- __activate_task(p, rq);
- if (TASK_PREEMPTS_CURR(p, rq))
- resched_task(rq->curr);
- }
-
- double_rq_unlock(this_rq, rq);
- local_irq_restore(flags);
- put_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
@@ -1310,6 +1689,7 @@ static void sched_migrate_task(task_t *p, int dest_cpu)
|| unlikely(cpu_is_offline(dest_cpu)))
goto out;
+ schedstat_inc(rq, smt_cnt);
/* force the process onto the specified CPU */
if (migrate_task(p, dest_cpu, &req)) {
/* Need to wait for migration thread (might exit: take ref). */
@@ -1326,17 +1706,18 @@ out:
}
/*
- * sched_balance_exec(): find the highest-level, exec-balance-capable
+ * 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.
*/
-void sched_balance_exec(void)
+void sched_exec(void)
{
struct sched_domain *tmp, *sd = NULL;
int new_cpu, this_cpu = get_cpu();
+ schedstat_inc(this_rq(), sbe_cnt);
/* Prefer the current CPU if there's only this task running */
if (this_rq()->nr_running <= 1)
goto out;
@@ -1345,9 +1726,11 @@ void sched_balance_exec(void)
if (tmp->flags & SD_BALANCE_EXEC)
sd = tmp;
+ schedstat_inc(sd, sbe_attempts);
if (sd) {
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;
@@ -1358,21 +1741,6 @@ out:
}
/*
- * double_lock_balance - lock the busiest runqueue, this_rq is locked already.
- */
-static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
-{
- if (unlikely(!spin_trylock(&busiest->lock))) {
- if (busiest < this_rq) {
- spin_unlock(&this_rq->lock);
- spin_lock(&busiest->lock);
- spin_lock(&this_rq->lock);
- } else
- spin_lock(&busiest->lock);
- }
-}
-
-/*
* pull_task - move a task from a remote runqueue to the local runqueue.
* Both runqueues must be locked.
*/
@@ -1486,6 +1854,15 @@ skip_queue:
idx++;
goto skip_bitmap;
}
+
+ /*
+ * Right now, this is the only place pull_task() is called,
+ * so we can safely collect pull_task() stats here rather than
+ * inside pull_task().
+ */
+ schedstat_inc(this_rq, pt_gained[idle]);
+ schedstat_inc(busiest, pt_lost[idle]);
+
pull_task(busiest, array, tmp, this_rq, dst_array, this_cpu);
pulled++;
@@ -1680,14 +2057,20 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
int nr_moved;
spin_lock(&this_rq->lock);
+ schedstat_inc(sd, lb_cnt[idle]);
group = find_busiest_group(sd, this_cpu, &imbalance, idle);
- if (!group)
+ if (!group) {
+ schedstat_inc(sd, lb_nobusyg[idle]);
goto out_balanced;
+ }
busiest = find_busiest_queue(group);
- if (!busiest)
+ if (!busiest) {
+ schedstat_inc(sd, lb_nobusyq[idle]);
goto out_balanced;
+ }
+
/*
* This should be "impossible", but since load
* balancing is inherently racy and statistical,
@@ -1698,6 +2081,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
goto out_balanced;
}
+ schedstat_add(sd, lb_imbalance[idle], imbalance);
+
nr_moved = 0;
if (busiest->nr_running > 1) {
/*
@@ -1714,6 +2099,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
spin_unlock(&this_rq->lock);
if (!nr_moved) {
+ schedstat_inc(sd, lb_failed[idle]);
sd->nr_balance_failed++;
if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
@@ -1768,19 +2154,27 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
unsigned long imbalance;
int nr_moved = 0;
+ schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE);
- if (!group)
+ if (!group) {
+ schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
goto out;
+ }
busiest = find_busiest_queue(group);
- if (!busiest || busiest == this_rq)
+ if (!busiest || busiest == this_rq) {
+ schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
goto out;
+ }
/* 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);
+ if (!nr_moved)
+ schedstat_inc(sd, lb_failed[NEWLY_IDLE]);
spin_unlock(&busiest->lock);
@@ -1820,40 +2214,39 @@ static void active_load_balance(runqueue_t *busiest, int busiest_cpu)
struct sched_group *group, *busy_group;
int i;
+ schedstat_inc(busiest, alb_cnt);
if (busiest->nr_running <= 1)
return;
for_each_domain(busiest_cpu, sd)
if (cpu_isset(busiest->push_cpu, sd->span))
break;
- if (!sd) {
- WARN_ON(1);
+ if (!sd)
return;
- }
- group = sd->groups;
+ group = sd->groups;
while (!cpu_isset(busiest_cpu, group->cpumask))
- group = group->next;
- busy_group = group;
+ group = group->next;
+ busy_group = group;
- group = sd->groups;
- do {
+ group = sd->groups;
+ do {
cpumask_t tmp;
runqueue_t *rq;
int push_cpu = 0;
- if (group == busy_group)
- goto next_group;
+ if (group == busy_group)
+ goto next_group;
cpus_and(tmp, group->cpumask, cpu_online_map);
if (!cpus_weight(tmp))
goto next_group;
- for_each_cpu_mask(i, tmp) {
+ for_each_cpu_mask(i, tmp) {
if (!idle_cpu(i))
goto next_group;
- push_cpu = i;
- }
+ push_cpu = i;
+ }
rq = cpu_rq(push_cpu);
@@ -1866,7 +2259,12 @@ static void active_load_balance(runqueue_t *busiest, int busiest_cpu)
if (unlikely(busiest == rq))
goto next_group;
double_lock_balance(busiest, rq);
- move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
+ if (move_tasks(rq, push_cpu, busiest, 1, sd, IDLE)) {
+ schedstat_inc(busiest, alb_lost);
+ schedstat_inc(rq, alb_gained);
+ } else {
+ schedstat_inc(busiest, alb_failed);
+ }
spin_unlock(&rq->lock);
next_group:
group = group->next;
@@ -1938,17 +2336,20 @@ static inline void idle_balance(int cpu, runqueue_t *rq)
static inline int wake_priority_sleeper(runqueue_t *rq)
{
+ int ret = 0;
#ifdef CONFIG_SCHED_SMT
+ spin_lock(&rq->lock);
/*
* If an SMT sibling task has been put to sleep for priority
* reasons reschedule the idle task to see if it can now run.
*/
if (rq->nr_running) {
resched_task(rq->idle);
- return 1;
+ ret = 1;
}
+ spin_unlock(&rq->lock);
#endif
- return 0;
+ return ret;
}
DEFINE_PER_CPU(struct kernel_stat, kstat);
@@ -2028,7 +2429,7 @@ void scheduler_tick(int user_ticks, int sys_ticks)
* timeslice. This makes it possible for interactive tasks
* to use up their timeslices at their highest priority levels.
*/
- if (unlikely(rt_task(p))) {
+ if (rt_task(p)) {
/*
* RR tasks need a special form of timeslice management.
* FIFO tasks have no timeslices.
@@ -2094,23 +2495,34 @@ out:
}
#ifdef CONFIG_SCHED_SMT
-static inline void wake_sleeping_dependent(int cpu, runqueue_t *rq)
+static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
{
- int i;
- struct sched_domain *sd = rq->sd;
+ struct sched_domain *sd = this_rq->sd;
cpumask_t sibling_map;
+ int i;
if (!(sd->flags & SD_SHARE_CPUPOWER))
return;
+ /*
+ * Unlock the current runqueue because we have to lock in
+ * CPU order to avoid deadlocks. Caller knows that we might
+ * unlock. We keep IRQs disabled.
+ */
+ spin_unlock(&this_rq->lock);
+
cpus_and(sibling_map, sd->span, cpu_online_map);
- for_each_cpu_mask(i, sibling_map) {
- runqueue_t *smt_rq;
- if (i == cpu)
- continue;
+ for_each_cpu_mask(i, sibling_map)
+ spin_lock(&cpu_rq(i)->lock);
+ /*
+ * We clear this CPU from the mask. This both simplifies the
+ * inner loop and keps this_rq locked when we exit:
+ */
+ cpu_clear(this_cpu, sibling_map);
- smt_rq = cpu_rq(i);
+ for_each_cpu_mask(i, sibling_map) {
+ runqueue_t *smt_rq = cpu_rq(i);
/*
* If an SMT sibling task is sleeping due to priority
@@ -2119,27 +2531,53 @@ static inline void wake_sleeping_dependent(int cpu, runqueue_t *rq)
if (smt_rq->curr == smt_rq->idle && smt_rq->nr_running)
resched_task(smt_rq->idle);
}
+
+ for_each_cpu_mask(i, sibling_map)
+ spin_unlock(&cpu_rq(i)->lock);
+ /*
+ * We exit with this_cpu's rq still held and IRQs
+ * still disabled:
+ */
}
-static inline int dependent_sleeper(int cpu, runqueue_t *rq, task_t *p)
+static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
{
- struct sched_domain *sd = rq->sd;
+ struct sched_domain *sd = this_rq->sd;
cpumask_t sibling_map;
+ prio_array_t *array;
int ret = 0, i;
+ task_t *p;
if (!(sd->flags & SD_SHARE_CPUPOWER))
return 0;
+ /*
+ * The same locking rules and details apply as for
+ * wake_sleeping_dependent():
+ */
+ spin_unlock(&this_rq->lock);
cpus_and(sibling_map, sd->span, cpu_online_map);
- for_each_cpu_mask(i, sibling_map) {
- runqueue_t *smt_rq;
- task_t *smt_curr;
+ for_each_cpu_mask(i, sibling_map)
+ spin_lock(&cpu_rq(i)->lock);
+ cpu_clear(this_cpu, sibling_map);
- if (i == cpu)
- continue;
+ /*
+ * Establish next task to be run - it might have gone away because
+ * we released the runqueue lock above:
+ */
+ if (!this_rq->nr_running)
+ goto out_unlock;
+ array = this_rq->active;
+ if (!array->nr_active)
+ array = this_rq->expired;
+ BUG_ON(!array->nr_active);
+
+ p = list_entry(array->queue[sched_find_first_bit(array->bitmap)].next,
+ task_t, run_list);
- smt_rq = cpu_rq(i);
- smt_curr = smt_rq->curr;
+ for_each_cpu_mask(i, sibling_map) {
+ runqueue_t *smt_rq = cpu_rq(i);
+ task_t *smt_curr = smt_rq->curr;
/*
* If a user task with lower static priority than the
@@ -2165,14 +2603,17 @@ static inline int dependent_sleeper(int cpu, runqueue_t *rq, task_t *p)
(smt_curr == smt_rq->idle && smt_rq->nr_running))
resched_task(smt_curr);
}
+out_unlock:
+ for_each_cpu_mask(i, sibling_map)
+ spin_unlock(&cpu_rq(i)->lock);
return ret;
}
#else
-static inline void wake_sleeping_dependent(int cpu, runqueue_t *rq)
+static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
{
}
-static inline int dependent_sleeper(int cpu, runqueue_t *rq, task_t *p)
+static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
{
return 0;
}
@@ -2209,7 +2650,17 @@ need_resched:
prev = current;
rq = this_rq();
+ /*
+ * The idle thread is not allowed to schedule!
+ * Remove this check after it has been exercised a bit.
+ */
+ if (unlikely(current == rq->idle) && current->state != TASK_RUNNING) {
+ printk(KERN_ERR "bad: scheduling from the idle thread!\n");
+ dump_stack();
+ }
+
release_kernel_lock(prev);
+ schedstat_inc(rq, sched_cnt);
now = sched_clock();
if (likely(now - prev->timestamp < NS_MAX_SLEEP_AVG))
run_time = now - prev->timestamp;
@@ -2242,13 +2693,33 @@ need_resched:
cpu = smp_processor_id();
if (unlikely(!rq->nr_running)) {
+go_idle:
idle_balance(cpu, rq);
if (!rq->nr_running) {
next = rq->idle;
rq->expired_timestamp = 0;
wake_sleeping_dependent(cpu, rq);
+ /*
+ * wake_sleeping_dependent() might have released
+ * the runqueue, so break out if we got new
+ * tasks meanwhile:
+ */
+ if (!rq->nr_running)
+ goto switch_tasks;
+ }
+ } else {
+ if (dependent_sleeper(cpu, rq)) {
+ schedstat_inc(rq, sched_goidle);
+ next = rq->idle;
goto switch_tasks;
}
+ /*
+ * dependent_sleeper() releases and reacquires the runqueue
+ * lock, hence go into the idle loop if the rq went
+ * empty meanwhile:
+ */
+ if (unlikely(!rq->nr_running))
+ goto go_idle;
}
array = rq->active;
@@ -2256,22 +2727,19 @@ need_resched:
/*
* Switch the active and expired arrays.
*/
+ schedstat_inc(rq, sched_switch);
rq->active = rq->expired;
rq->expired = array;
array = rq->active;
rq->expired_timestamp = 0;
rq->best_expired_prio = MAX_PRIO;
- }
+ } else
+ schedstat_inc(rq, sched_noswitch);
idx = sched_find_first_bit(array->bitmap);
queue = array->queue + idx;
next = list_entry(queue->next, task_t, run_list);
- if (dependent_sleeper(cpu, rq, next)) {
- next = rq->idle;
- goto switch_tasks;
- }
-
if (!rt_task(next) && next->activated > 0) {
unsigned long long delta = now - next->timestamp;
@@ -2297,6 +2765,7 @@ switch_tasks:
}
prev->timestamp = now;
+ sched_info_switch(prev, next);
if (likely(prev != next)) {
next->timestamp = now;
rq->nr_switches++;
@@ -2313,7 +2782,7 @@ switch_tasks:
reacquire_kernel_lock(current);
preempt_enable_no_resched();
- if (test_thread_flag(TIF_NEED_RESCHED))
+ if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
goto need_resched;
}
@@ -3008,6 +3477,7 @@ asmlinkage long sys_sched_yield(void)
prio_array_t *array = current->array;
prio_array_t *target = rq->expired;
+ schedstat_inc(rq, yld_cnt);
/*
* We implement yielding by moving the task into the expired
* queue.
@@ -3015,9 +3485,16 @@ asmlinkage long sys_sched_yield(void)
* (special rule: RT tasks will just roundrobin in the active
* array.)
*/
- if (unlikely(rt_task(current)))
+ if (rt_task(current))
target = rq->active;
+ if (current->array->nr_active == 1) {
+ schedstat_inc(rq, yld_act_empty);
+ if (!rq->expired->nr_active)
+ schedstat_inc(rq, yld_both_empty);
+ } else if (!rq->expired->nr_active)
+ schedstat_inc(rq, yld_exp_empty);
+
dequeue_task(current, array);
enqueue_task(current, target);
@@ -3268,21 +3745,20 @@ void show_state(void)
void __devinit init_idle(task_t *idle, int cpu)
{
- runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(task_cpu(idle));
+ runqueue_t *rq = cpu_rq(cpu);
unsigned long flags;
- local_irq_save(flags);
- double_rq_lock(idle_rq, rq);
-
- idle_rq->curr = idle_rq->idle = idle;
- deactivate_task(idle, rq);
+ idle->sleep_avg = 0;
+ idle->interactive_credit = 0;
idle->array = NULL;
idle->prio = MAX_PRIO;
idle->state = TASK_RUNNING;
set_task_cpu(idle, cpu);
- double_rq_unlock(idle_rq, rq);
+
+ spin_lock_irqsave(&rq->lock, flags);
+ rq->curr = rq->idle = idle;
set_tsk_need_resched(idle);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&rq->lock, flags);
/* Set the preempt count _outside_ the spinlocks! */
#ifdef CONFIG_PREEMPT
@@ -3364,7 +3840,7 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed);
* Move (not current) task off this cpu, onto dest cpu. We're doing
* this because either it can't run here any more (set_cpus_allowed()
* away from this CPU, or CPU going down), or because we're
- * attempting to rebalance this task on exec (sched_balance_exec).
+ * attempting to rebalance this task on exec (sched_exec).
*
* So we race with normal scheduler movements, but that's OK, as long
* as the task is no longer on this CPU.
@@ -3376,7 +3852,7 @@ static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
if (unlikely(cpu_is_offline(dest_cpu)))
return;
- rq_src = cpu_rq(src_cpu);
+ rq_src = cpu_rq(src_cpu);
rq_dest = cpu_rq(dest_cpu);
double_rq_lock(rq_src, rq_dest);
@@ -3481,7 +3957,7 @@ wait_to_die:
}
#ifdef CONFIG_HOTPLUG_CPU
-/* migrate_all_tasks - function to migrate all tasks from the dead cpu. */
+/* migrate_all_tasks - function to migrate all tasks from the dead cpu. */
static void migrate_all_tasks(int src_cpu)
{
struct task_struct *tsk, *t;
@@ -3514,15 +3990,16 @@ static void migrate_all_tasks(int src_cpu)
cpus_setall(tsk->cpus_allowed);
dest_cpu = any_online_cpu(tsk->cpus_allowed);
- /* Don't tell them about moving exiting tasks
- or kernel threads (both mm NULL), since
- they never leave kernel. */
+ /*
+ * Don't tell them about moving exiting tasks
+ * or kernel threads (both mm NULL), since
+ * they never leave kernel.
+ */
if (tsk->mm && printk_ratelimit())
printk(KERN_INFO "process %d (%s) no "
"longer affine to cpu%d\n",
tsk->pid, tsk->comm, src_cpu);
}
-
__migrate_task(tsk, src_cpu, dest_cpu);
} while_each_thread(t, tsk);
@@ -3603,7 +4080,7 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
rq->idle->static_prio = MAX_PRIO;
__setscheduler(rq->idle, SCHED_NORMAL, 0);
task_rq_unlock(rq, &flags);
- BUG_ON(rq->nr_running != 0);
+ BUG_ON(rq->nr_running != 0);
/* No need to migrate the tasks: it was best-effort if
* they didn't do lock_cpu_hotplug(). Just wake up
@@ -3618,7 +4095,7 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
complete(&req->done);
}
spin_unlock_irq(&rq->lock);
- break;
+ break;
#endif
}
return NOTIFY_OK;
@@ -3660,7 +4137,7 @@ EXPORT_SYMBOL(kernel_flag);
#ifdef CONFIG_SMP
/* Attach the domain 'sd' to 'cpu' as its base domain */
-void cpu_attach_domain(struct sched_domain *sd, int cpu)
+static void cpu_attach_domain(struct sched_domain *sd, int cpu)
{
migration_req_t req;
unsigned long flags;
@@ -3691,123 +4168,326 @@ void cpu_attach_domain(struct sched_domain *sd, int cpu)
unlock_cpu_hotplug();
}
-#ifdef ARCH_HAS_SCHED_DOMAIN
-extern void __init arch_init_sched_domains(void);
-#else
-static struct sched_group sched_group_cpus[NR_CPUS];
-static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
#ifdef CONFIG_NUMA
-static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static DEFINE_PER_CPU(struct sched_domain, node_domains);
-static void __init arch_init_sched_domains(void)
+/**
+ * find_next_best_node - find the next node to include in a sched_domain
+ * @node: node whose sched_domain we're building
+ * @used_nodes: nodes already in the sched_domain
+ *
+ * Find the next node to include in a given scheduling domain. Simply
+ * finds the closest node not already in the @used_nodes map.
+ *
+ * Should use nodemask_t.
+ */
+static int __init find_next_best_node(int node, unsigned long *used_nodes)
+{
+ int i, n, val, min_val, best_node = 0;
+
+ min_val = INT_MAX;
+
+ for (i = 0; i < numnodes; i++) {
+ /* Start at @node */
+ n = (node + i) % numnodes;
+
+ /* Skip already used nodes */
+ if (test_bit(n, used_nodes))
+ continue;
+
+ /* Simple min distance search */
+ val = node_distance(node, i);
+
+ if (val < min_val) {
+ min_val = val;
+ best_node = n;
+ }
+ }
+
+ set_bit(best_node, used_nodes);
+ return best_node;
+}
+
+/**
+ * sched_domain_node_span - get a cpumask for a node's sched_domain
+ * @node: node whose cpumask we're constructing
+ * @size: number of nodes to include in this span
+ *
+ * Given a node, construct a good cpumask for its sched_domain to span. It
+ * should be one that prevents unnecessary balancing, but also spreads tasks
+ * out optimally.
+ */
+cpumask_t __init sched_domain_node_span(int node, int size)
{
int i;
- struct sched_group *first_node = NULL, *last_node = NULL;
+ cpumask_t span;
+ DECLARE_BITMAP(used_nodes, MAX_NUMNODES);
- /* Set up domains */
- for_each_cpu(i) {
- int node = cpu_to_node(i);
- cpumask_t nodemask = node_to_cpumask(node);
- struct sched_domain *node_sd = &per_cpu(node_domains, i);
- struct sched_domain *cpu_sd = &per_cpu(cpu_domains, i);
+ cpus_clear(span);
+ bitmap_zero(used_nodes, MAX_NUMNODES);
- *node_sd = SD_NODE_INIT;
- node_sd->span = cpu_possible_map;
- node_sd->groups = &sched_group_nodes[cpu_to_node(i)];
+ for (i = 0; i < size; i++) {
+ int next_node = find_next_best_node(node, used_nodes);
+ cpumask_t nodemask;
- *cpu_sd = SD_CPU_INIT;
- cpus_and(cpu_sd->span, nodemask, cpu_possible_map);
- cpu_sd->groups = &sched_group_cpus[i];
- cpu_sd->parent = node_sd;
+ nodemask = node_to_cpumask(next_node);
+ cpus_or(span, span, nodemask);
}
- /* Set up groups */
- for (i = 0; i < MAX_NUMNODES; i++) {
- cpumask_t tmp = node_to_cpumask(i);
- cpumask_t nodemask;
- struct sched_group *first_cpu = NULL, *last_cpu = NULL;
- struct sched_group *node = &sched_group_nodes[i];
- int j;
+ return span;
+}
+#endif /* CONFIG_NUMA */
+
+#ifdef CONFIG_SCHED_SMT
+static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
+static struct sched_group sched_group_cpus[NR_CPUS];
+__init static int cpu_to_cpu_group(int cpu)
+{
+ return cpu;
+}
+#endif
+
+static DEFINE_PER_CPU(struct sched_domain, phys_domains);
+static struct sched_group sched_group_phys[NR_CPUS];
+__init static int cpu_to_phys_group(int cpu)
+{
+#ifdef CONFIG_SCHED_SMT
+ return first_cpu(cpu_sibling_map[cpu]);
+#else
+ return cpu;
+#endif
+}
- cpus_and(nodemask, tmp, cpu_possible_map);
+#ifdef CONFIG_NUMA
- if (cpus_empty(nodemask))
- continue;
+/* Number of nearby nodes in a node's scheduling domain */
+#define SD_NODES_PER_DOMAIN 4
+
+static DEFINE_PER_CPU(struct sched_domain, node_domains);
+static struct sched_group sched_group_nodes[MAX_NUMNODES];
+__init static int cpu_to_node_group(int cpu)
+{
+ return cpu_to_node(cpu);
+}
+#endif
- node->cpumask = nodemask;
- node->cpu_power = SCHED_LOAD_SCALE * cpus_weight(node->cpumask);
+/* Groups for isolated scheduling domains */
+static struct sched_group sched_group_isolated[NR_CPUS];
- for_each_cpu_mask(j, node->cpumask) {
- struct sched_group *cpu = &sched_group_cpus[j];
+/* cpus with isolated domains */
+cpumask_t __initdata cpu_isolated_map = CPU_MASK_NONE;
- cpus_clear(cpu->cpumask);
- cpu_set(j, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
+__init static int cpu_to_isolated_group(int cpu)
+{
+ return cpu;
+}
- if (!first_cpu)
- first_cpu = cpu;
- if (last_cpu)
- last_cpu->next = cpu;
- last_cpu = cpu;
- }
- last_cpu->next = first_cpu;
+/* Setup the mask of cpus configured for isolated domains */
+static int __init isolated_cpu_setup(char *str)
+{
+ int ints[NR_CPUS], i;
- if (!first_node)
- first_node = node;
- if (last_node)
- last_node->next = node;
- last_node = node;
- }
- last_node->next = first_node;
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ cpus_clear(cpu_isolated_map);
+ for (i = 1; i <= ints[0]; i++)
+ cpu_set(ints[i], cpu_isolated_map);
+ return 1;
+}
- mb();
- for_each_cpu(i) {
- struct sched_domain *cpu_sd = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_sd, i);
+__setup ("isolcpus=", isolated_cpu_setup);
+
+/*
+ * init_sched_build_groups takes an array of groups, the cpumask we wish
+ * to span, and a pointer to a function which identifies what group a CPU
+ * belongs to. The return value of group_fn must be a valid index into the
+ * groups[] array, and must be >= 0 and < NR_CPUS (due to the fact that we
+ * keep track of groups covered with a cpumask_t).
+ *
+ * init_sched_build_groups will build a circular linked list of the groups
+ * covered by the given span, and will set each group's ->cpumask correctly,
+ * and ->cpu_power to 0.
+ */
+__init static void init_sched_build_groups(struct sched_group groups[],
+ cpumask_t span, int (*group_fn)(int cpu))
+{
+ struct sched_group *first = NULL, *last = NULL;
+ cpumask_t covered = CPU_MASK_NONE;
+ int i;
+
+ for_each_cpu_mask(i, span) {
+ int group = group_fn(i);
+ struct sched_group *sg = &groups[group];
+ int j;
+
+ if (cpu_isset(i, covered))
+ continue;
+
+ sg->cpumask = CPU_MASK_NONE;
+ sg->cpu_power = 0;
+
+ for_each_cpu_mask(j, span) {
+ if (group_fn(j) != group)
+ continue;
+
+ cpu_set(j, covered);
+ cpu_set(j, sg->cpumask);
+ }
+ if (!first)
+ first = sg;
+ if (last)
+ last->next = sg;
+ last = sg;
}
+ last->next = first;
}
-#else /* !CONFIG_NUMA */
-static void __init arch_init_sched_domains(void)
+__init static void arch_init_sched_domains(void)
{
int i;
- struct sched_group *first_cpu = NULL, *last_cpu = NULL;
+ 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_complement(cpu_default_map, cpu_isolated_map);
+ cpus_and(cpu_default_map, cpu_default_map, cpu_possible_map);
/* Set up domains */
for_each_cpu(i) {
- struct sched_domain *cpu_sd = &per_cpu(cpu_domains, i);
+ 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);
+
+ /*
+ * Set up isolated domains.
+ * Unlike those of other cpus, the domains and groups are
+ * single level, and span a single cpu.
+ */
+ if (cpu_isset(i, cpu_isolated_map)) {
+#ifdef CONFIG_SCHED_SMT
+ sd = &per_cpu(cpu_domains, i);
+#else
+ sd = &per_cpu(phys_domains, i);
+#endif
+ group = cpu_to_isolated_group(i);
+ *sd = SD_CPU_INIT;
+ cpu_set(i, sd->span);
+ sd->balance_interval = INT_MAX; /* Don't balance */
+ sd->flags = 0; /* Avoid WAKE_ */
+ sd->groups = &sched_group_isolated[group];
+ printk(KERN_INFO "Setting up cpu %d isolated.\n", i);
+ /* Single level, so continue with next cpu */
+ continue;
+ }
+
+#ifdef CONFIG_NUMA
+ sd = &per_cpu(node_domains, i);
+ group = cpu_to_node_group(i);
+ *sd = SD_NODE_INIT;
+ /* FIXME: should be multilevel, in arch code */
+ sd->span = sched_domain_node_span(i, SD_NODES_PER_DOMAIN);
+ cpus_and(sd->span, sd->span, cpu_default_map);
+ sd->groups = &sched_group_nodes[group];
+#endif
+
+ p = sd;
+ sd = &per_cpu(phys_domains, i);
+ group = cpu_to_phys_group(i);
+ *sd = SD_CPU_INIT;
+ sd->span = nodemask;
+ sd->parent = p;
+ sd->groups = &sched_group_phys[group];
+
+#ifdef CONFIG_SCHED_SMT
+ p = sd;
+ sd = &per_cpu(cpu_domains, i);
+ 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);
+ sd->parent = p;
+ sd->groups = &sched_group_cpus[group];
+#endif
+ }
+
+#ifdef CONFIG_SCHED_SMT
+ /* Set up CPU (sibling) groups */
+ for_each_cpu(i) {
+ cpumask_t this_sibling_map = cpu_sibling_map[i];
+ cpus_and(this_sibling_map, this_sibling_map, cpu_default_map);
+ if (i != first_cpu(this_sibling_map))
+ continue;
+
+ init_sched_build_groups(sched_group_cpus, this_sibling_map,
+ &cpu_to_cpu_group);
+ }
+#endif
+
+ /* Set up isolated groups */
+ for_each_cpu_mask(i, cpu_isolated_map) {
+ cpumask_t mask;
+ cpus_clear(mask);
+ cpu_set(i, mask);
+ init_sched_build_groups(sched_group_isolated, mask,
+ &cpu_to_isolated_group);
+ }
+
+ /* Set up physical groups */
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ cpumask_t nodemask = node_to_cpumask(i);
+
+ cpus_and(nodemask, nodemask, cpu_default_map);
+ if (cpus_empty(nodemask))
+ continue;
- *cpu_sd = SD_CPU_INIT;
- cpu_sd->span = cpu_possible_map;
- cpu_sd->groups = &sched_group_cpus[i];
+ init_sched_build_groups(sched_group_phys, nodemask,
+ &cpu_to_phys_group);
}
- /* Set up CPU groups */
- for_each_cpu_mask(i, cpu_possible_map) {
- struct sched_group *cpu = &sched_group_cpus[i];
+#ifdef CONFIG_NUMA
+ /* Set up node groups */
+ init_sched_build_groups(sched_group_nodes, cpu_default_map,
+ &cpu_to_node_group);
+#endif
- cpus_clear(cpu->cpumask);
- cpu_set(i, cpu->cpumask);
- cpu->cpu_power = SCHED_LOAD_SCALE;
+ /* Calculate CPU power for physical packages and nodes */
+ for_each_cpu_mask(i, cpu_default_map) {
+ int power;
+ struct sched_domain *sd;
+#ifdef CONFIG_SCHED_SMT
+ sd = &per_cpu(cpu_domains, i);
+ power = SCHED_LOAD_SCALE;
+ sd->groups->cpu_power = power;
+#endif
+
+ sd = &per_cpu(phys_domains, i);
+ power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE *
+ (cpus_weight(sd->groups->cpumask)-1) / 10;
+ sd->groups->cpu_power = power;
- if (!first_cpu)
- first_cpu = cpu;
- if (last_cpu)
- last_cpu->next = cpu;
- last_cpu = cpu;
+#ifdef CONFIG_NUMA
+ if (i == first_cpu(sd->groups->cpumask)) {
+ /* Only add "power" once for each physical package. */
+ sd = &per_cpu(node_domains, i);
+ sd->groups->cpu_power += power;
+ }
+#endif
}
- last_cpu->next = first_cpu;
- mb(); /* domains were modified outside the lock */
+ /* Attach the domains */
for_each_cpu(i) {
- struct sched_domain *cpu_sd = &per_cpu(cpu_domains, i);
- cpu_attach_domain(cpu_sd, i);
+ struct sched_domain *sd;
+#ifdef CONFIG_SCHED_SMT
+ sd = &per_cpu(cpu_domains, i);
+#else
+ sd = &per_cpu(phys_domains, i);
+#endif
+ cpu_attach_domain(sd, i);
}
}
-#endif /* CONFIG_NUMA */
-#endif /* ARCH_HAS_SCHED_DOMAIN */
-
#define SCHED_DOMAIN_DEBUG
#ifdef SCHED_DOMAIN_DEBUG
void sched_domain_debug(void)
@@ -3959,21 +4639,20 @@ void __init sched_init(void)
__set_bit(MAX_PRIO, array->bitmap);
}
}
- /*
- * We have to do a little magic to get the first
- * thread right in SMP mode.
- */
- rq = this_rq();
- rq->curr = current;
- rq->idle = current;
- set_task_cpu(current, smp_processor_id());
- wake_up_forked_process(current);
/*
* The boot idle thread does lazy MMU switching as well:
*/
atomic_inc(&init_mm.mm_count);
enter_lazy_tlb(&init_mm, current);
+
+ /*
+ * Make us the idle thread. Technically, schedule() should not be
+ * called from this thread, however somewhere below it might be,
+ * but because we are the idle thread, we just pick up running again
+ * when this runqueue becomes "idle".
+ */
+ init_idle(current, smp_processor_id());
}
#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
diff --git a/kernel/signal.c b/kernel/signal.c
index 6ea3d407e3235..e5d6cbc50c1e2 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1243,6 +1243,25 @@ force_sig(int sig, struct task_struct *p)
force_sig_info(sig, (void*)1L, p);
}
+/*
+ * When things go south during signal handling, we
+ * will force a SIGSEGV. And if the signal that caused
+ * the problem was already a SIGSEGV, we'll want to
+ * make sure we don't even try to deliver the signal..
+ */
+int
+force_sigsegv(int sig, struct task_struct *p)
+{
+ if (sig == SIGSEGV) {
+ unsigned long flags;
+ spin_lock_irqsave(&p->sighand->siglock, flags);
+ p->sighand->action[sig - 1].sa.sa_handler = SIG_DFL;
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
+ }
+ force_sig(SIGSEGV, p);
+ return 0;
+}
+
int
kill_pg(pid_t pgrp, int sig, int priv)
{
@@ -1724,7 +1743,8 @@ static inline int handle_group_stop(void)
return 1;
}
-int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs, void *cookie)
+int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
+ struct pt_regs *regs, void *cookie)
{
sigset_t *mask = &current->blocked;
int signr = 0;
@@ -1793,8 +1813,15 @@ relock:
ka = &current->sighand->action[signr-1];
if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */
continue;
- if (ka->sa.sa_handler != SIG_DFL) /* Run the handler. */
+ if (ka->sa.sa_handler != SIG_DFL) {
+ /* Run the handler. */
+ *return_ka = *ka;
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
break; /* will return non-zero "signr" value */
+ }
/*
* Now we are doing the default action for this signal.
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 2c5c58279f81a..99a0af0ed9a8a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -42,6 +42,7 @@
#include <linux/dcache.h>
#include <asm/uaccess.h>
+#include <asm/processor.h>
#ifdef CONFIG_ROOT_NFS
#include <linux/nfs_fs.h>
@@ -116,12 +117,6 @@ extern int sysctl_userprocess_debug;
extern int sysctl_hz_timer;
-#if defined(CONFIG_PPC32) && defined(CONFIG_6xx)
-extern unsigned long powersave_nap;
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos);
-#endif
-
#ifdef CONFIG_BSD_PROCESS_ACCT
extern int acct_parm[];
#endif
@@ -149,6 +144,10 @@ extern ctl_table random_table[];
extern ctl_table pty_table[];
#endif
+#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
+int sysctl_legacy_va_layout;
+#endif
+
/* /proc declarations: */
#ifdef CONFIG_PROC_FS
@@ -295,7 +294,7 @@ static ctl_table kern_table[] = {
.procname = "tainted",
.data = &tainted,
.maxlen = sizeof(int),
- .mode = 0644,
+ .mode = 0444,
.proc_handler = &proc_dointvec,
},
{
@@ -361,22 +360,6 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
-#if defined(CONFIG_PPC32) && defined(CONFIG_6xx)
- {
- .ctl_name = KERN_PPC_POWERSAVE_NAP,
- .procname = "powersave-nap",
- .data = &powersave_nap,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = KERN_PPC_L2CR,
- .procname = "l2cr",
- .mode = 0644,
- .proc_handler = &proc_dol2crvec,
- },
-#endif
{
.ctl_name = KERN_CTLALTDEL,
.procname = "ctrl-alt-del",
@@ -805,6 +788,18 @@ static ctl_table vm_table[] = {
.strategy = &sysctl_intvec,
.extra1 = &zero,
},
+#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
+ {
+ .ctl_name = VM_LEGACY_VA_LAYOUT,
+ .procname = "legacy_va_layout",
+ .data = &sysctl_legacy_va_layout,
+ .maxlen = sizeof(sysctl_legacy_va_layout),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero,
+ },
+#endif
{ .ctl_name = 0 }
};
diff --git a/lib/Makefile b/lib/Makefile
index f80da45800595..b62c9ef212edc 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,12 +5,9 @@
lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
- kobject.o idr.o div64.o parser.o int_sqrt.o \
+ kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
bitmap.o extable.o
-# hack for now till some static code uses krefs, then it can move up above...
-obj-y += kref.o
-
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff --git a/lib/kobject.c b/lib/kobject.c
index 781f3e8966955..a971b8e55e6b7 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -58,14 +58,11 @@ static int create_dir(struct kobject * kobj)
return error;
}
-
static inline struct kobject * to_kobj(struct list_head * entry)
{
return container_of(entry,struct kobject,entry);
}
-
-#ifdef CONFIG_HOTPLUG
static int get_kobj_path_length(struct kset *kset, struct kobject *kobj)
{
int length = 1;
@@ -98,6 +95,31 @@ static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path,
pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
}
+/**
+ * kobject_get_path - generate and return the path associated with a given kobj
+ * and kset pair. The result must be freed by the caller with kfree().
+ *
+ * @kset: kset in question, with which to build the path
+ * @kobj: kobject in question, with which to build the path
+ * @gfp_mask: the allocation type used to allocate the path
+ */
+char * kobject_get_path(struct kset *kset, struct kobject *kobj, int gfp_mask)
+{
+ char *path;
+ int len;
+
+ len = get_kobj_path_length(kset, kobj);
+ path = kmalloc(len, gfp_mask);
+ if (!path)
+ return NULL;
+ memset(path, 0x00, len);
+ fill_kobj_path(kset, kobj, path, len);
+
+ return path;
+}
+
+#ifdef CONFIG_HOTPLUG
+
#define BUFFER_SIZE 1024 /* should be enough memory for the env */
#define NUM_ENVP 32 /* number of env pointers */
static unsigned long sequence_num;
@@ -112,7 +134,6 @@ static void kset_hotplug(const char *action, struct kset *kset,
char *scratch;
int i = 0;
int retval;
- int kobj_path_length;
char *kobj_path = NULL;
char *name = NULL;
unsigned long seq;
@@ -163,12 +184,9 @@ static void kset_hotplug(const char *action, struct kset *kset,
envp [i++] = scratch;
scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
- kobj_path_length = get_kobj_path_length (kset, kobj);
- kobj_path = kmalloc (kobj_path_length, GFP_KERNEL);
+ kobj_path = kobject_get_path(kset, kobj, GFP_KERNEL);
if (!kobj_path)
goto exit;
- memset (kobj_path, 0x00, kobj_path_length);
- fill_kobj_path (kset, kobj, kobj_path, kobj_path_length);
envp [i++] = scratch;
scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;
@@ -225,10 +243,9 @@ void kobject_hotplug(const char *action, struct kobject *kobj)
* kobject_init - initialize object.
* @kobj: object in question.
*/
-
void kobject_init(struct kobject * kobj)
{
- atomic_set(&kobj->refcount,1);
+ kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
kobj->kset = kset_get(kobj->kset);
}
@@ -325,7 +342,7 @@ int kobject_register(struct kobject * kobj)
* @kobj: object.
* @name: name.
*
- * If strlen(name) < KOBJ_NAME_LEN, then use a dynamically allocated
+ * If strlen(name) >= KOBJ_NAME_LEN, then use a dynamically allocated
* string that @kobj->k_name points to. Otherwise, use the static
* @kobj->name array.
*/
@@ -429,10 +446,8 @@ void kobject_unregister(struct kobject * kobj)
struct kobject * kobject_get(struct kobject * kobj)
{
- if (kobj) {
- WARN_ON(!atomic_read(&kobj->refcount));
- atomic_inc(&kobj->refcount);
- }
+ if (kobj)
+ kref_get(&kobj->kref);
return kobj;
}
@@ -459,17 +474,21 @@ void kobject_cleanup(struct kobject * kobj)
kobject_put(parent);
}
+static void kobject_release(struct kref *kref)
+{
+ kobject_cleanup(container_of(kref, struct kobject, kref));
+}
+
/**
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and if 0, call kobject_cleanup().
*/
-
void kobject_put(struct kobject * kobj)
{
- if (atomic_dec_and_test(&kobj->refcount))
- kobject_cleanup(kobj);
+ if (kobj)
+ kref_put(&kobj->kref, kobject_release);
}
@@ -626,7 +645,7 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
}
}
-
+EXPORT_SYMBOL(kobject_get_path);
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister);
diff --git a/lib/kref.c b/lib/kref.c
index ee141adbf2e55..2218b7ae7db6f 100644
--- a/lib/kref.c
+++ b/lib/kref.c
@@ -11,48 +11,45 @@
*
*/
-/* #define DEBUG */
-
#include <linux/kref.h>
#include <linux/module.h>
/**
* kref_init - initialize object.
* @kref: object in question.
- * @release: pointer to a function that will clean up the object
- * when the last reference to the object is released.
- * This pointer is required.
*/
-void kref_init(struct kref *kref, void (*release)(struct kref *kref))
+void kref_init(struct kref *kref)
{
- WARN_ON(release == NULL);
atomic_set(&kref->refcount,1);
- kref->release = release;
}
/**
* kref_get - increment refcount for object.
* @kref: object.
*/
-struct kref *kref_get(struct kref *kref)
+void kref_get(struct kref *kref)
{
WARN_ON(!atomic_read(&kref->refcount));
atomic_inc(&kref->refcount);
- return kref;
}
/**
* kref_put - decrement refcount for object.
* @kref: object.
+ * @release: pointer to the function that will clean up the object when the
+ * last reference to the object is released.
+ * This pointer is required, and it is not acceptable to pass kfree
+ * in as this function.
*
- * Decrement the refcount, and if 0, call kref->release().
+ * Decrement the refcount, and if 0, call release().
*/
-void kref_put(struct kref *kref)
+void kref_put(struct kref *kref, void (*release) (struct kref *kref))
{
- if (atomic_dec_and_test(&kref->refcount)) {
- pr_debug("kref cleaning up\n");
- kref->release(kref);
- }
+ WARN_ON(release == NULL);
+ WARN_ON(release == (void (*)(struct kref *))kfree);
+
+ if (atomic_dec_and_test(&kref->refcount))
+ release(kref);
}
EXPORT_SYMBOL(kref_init);
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 966135b90ff28..092d851764909 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -259,6 +259,7 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
unsigned long i, count, total = 0;
unsigned long idx;
unsigned long *map;
+ int gofast = 0;
BUG_ON(!bdata->node_bootmem_map);
@@ -267,14 +268,32 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
page = virt_to_page(phys_to_virt(bdata->node_boot_start));
idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
map = bdata->node_bootmem_map;
+ /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */
+ if (bdata->node_boot_start == 0 ||
+ ffs(bdata->node_boot_start) - PAGE_SHIFT > ffs(BITS_PER_LONG))
+ gofast = 1;
for (i = 0; i < idx; ) {
unsigned long v = ~map[i / BITS_PER_LONG];
- if (v) {
+ if (gofast && v == ~0UL) {
+ int j;
+
+ count += BITS_PER_LONG;
+ __ClearPageReserved(page);
+ set_page_count(page, 1);
+ for (j = 1; j < BITS_PER_LONG; j++) {
+ if (j + 16 < BITS_PER_LONG)
+ prefetchw(page + j + 16);
+ __ClearPageReserved(page + j);
+ }
+ __free_pages(page, ffs(BITS_PER_LONG)-1);
+ i += BITS_PER_LONG;
+ page += BITS_PER_LONG;
+ } else if (v) {
unsigned long m;
for (m = 1; m && i < idx; m<<=1, page++, i++) {
if (v & m) {
count++;
- ClearPageReserved(page);
+ __ClearPageReserved(page);
set_page_count(page, 1);
__free_page(page);
}
@@ -294,7 +313,7 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
count = 0;
for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
count++;
- ClearPageReserved(page);
+ __ClearPageReserved(page);
set_page_count(page, 1);
__free_page(page);
}
diff --git a/mm/filemap.c b/mm/filemap.c
index b32b51cc29ad8..4db9ba3d152b9 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -60,7 +60,6 @@
* ->swap_list_lock
* ->swap_device_lock (exclusive_swap_page, others)
* ->mapping->tree_lock
- * ->page_map_lock() (try_to_unmap_file)
*
* ->i_sem
* ->i_mmap_lock (truncate->unmap_mapping_range)
@@ -83,16 +82,20 @@
* ->sb_lock (fs/fs-writeback.c)
* ->mapping->tree_lock (__sync_single_inode)
*
+ * ->i_mmap_lock
+ * ->anon_vma.lock (vma_adjust)
+ *
+ * ->anon_vma.lock
+ * ->page_table_lock (anon_vma_prepare and various)
+ *
* ->page_table_lock
* ->swap_device_lock (try_to_unmap_one)
* ->private_lock (try_to_unmap_one)
* ->tree_lock (try_to_unmap_one)
* ->zone.lru_lock (follow_page->mark_page_accessed)
- * ->page_map_lock() (page_add_anon_rmap)
- * ->tree_lock (page_remove_rmap->set_page_dirty)
- * ->private_lock (page_remove_rmap->set_page_dirty)
- * ->inode_lock (page_remove_rmap->set_page_dirty)
- * ->anon_vma.lock (anon_vma_prepare)
+ * ->private_lock (page_remove_rmap->set_page_dirty)
+ * ->tree_lock (page_remove_rmap->set_page_dirty)
+ * ->inode_lock (page_remove_rmap->set_page_dirty)
* ->inode_lock (zap_pte_range->set_page_dirty)
* ->private_lock (zap_pte_range->__set_page_dirty_buffers)
*
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6c522e127033d..3c96ecf1b5a1e 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -123,6 +123,7 @@ static int __init hugetlb_setup(char *s)
}
__setup("hugepages=", hugetlb_setup);
+#ifdef CONFIG_SYSCTL
static void update_and_free_page(struct page *page)
{
int i;
@@ -188,7 +189,6 @@ static unsigned long set_max_huge_pages(unsigned long count)
return nr_huge_pages;
}
-#ifdef CONFIG_SYSCTL
int hugetlb_sysctl_handler(struct ctl_table *table, int write,
struct file *file, void __user *buffer,
size_t *length, loff_t *ppos)
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index d06eabbf74f0b..caaa6c34ae44b 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -132,7 +132,6 @@ static int get_nodes(unsigned long *nodes, unsigned long __user *nmask,
unsigned long nlongs;
unsigned long endmask;
- --maxnode;
bitmap_zero(nodes, MAX_NUMNODES);
if (maxnode == 0 || !nmask)
return 0;
diff --git a/mm/mmap.c b/mm/mmap.c
index 04dc9e2849183..87536f8283157 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1018,7 +1018,7 @@ EXPORT_SYMBOL(do_mmap_pgoff);
* This function "knows" that -ENOMEM has the bits set.
*/
#ifndef HAVE_ARCH_UNMAPPED_AREA
-static inline unsigned long
+unsigned long
arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
{
@@ -1062,12 +1062,116 @@ full_search:
addr = vma->vm_end;
}
}
-#else
-extern unsigned long
-arch_get_unmapped_area(struct file *, unsigned long, unsigned long,
- unsigned long, unsigned long);
#endif
+void arch_unmap_area(struct vm_area_struct *area)
+{
+ /*
+ * Is this a new hole at the lowest possible address?
+ */
+ if (area->vm_start >= TASK_UNMAPPED_BASE &&
+ area->vm_start < area->vm_mm->free_area_cache)
+ area->vm_mm->free_area_cache = area->vm_start;
+}
+
+/*
+ * This mmap-allocator allocates new areas top-down from below the
+ * stack's low limit (the base):
+ */
+unsigned long
+arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
+ const unsigned long len, const unsigned long pgoff,
+ const unsigned long flags)
+{
+ struct vm_area_struct *vma, *prev_vma;
+ struct mm_struct *mm = current->mm;
+ unsigned long base = mm->mmap_base, addr = addr0;
+ int first_time = 1;
+
+ /* requested length too big for entire address space */
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ /* dont allow allocations above current base */
+ if (mm->free_area_cache > base)
+ mm->free_area_cache = base;
+
+ /* requesting a specific address */
+ if (addr) {
+ addr = PAGE_ALIGN(addr);
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+
+try_again:
+ /* make sure it can fit in the remaining address space */
+ if (mm->free_area_cache < len)
+ goto fail;
+
+ /* either no address requested or cant fit in requested address hole */
+ addr = (mm->free_area_cache - len) & PAGE_MASK;
+ do {
+ /*
+ * Lookup failure means no vma is above this address,
+ * i.e. return with success:
+ */
+ if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
+ return addr;
+
+ /*
+ * new region fits between prev_vma->vm_end and
+ * vma->vm_start, use it:
+ */
+ if (addr+len <= vma->vm_start &&
+ (!prev_vma || (addr >= prev_vma->vm_end)))
+ /* remember the address as a hint for next time */
+ return (mm->free_area_cache = addr);
+ else
+ /* pull free_area_cache down to the first hole */
+ if (mm->free_area_cache == vma->vm_end)
+ mm->free_area_cache = vma->vm_start;
+
+ /* try just below the current vma->vm_start */
+ addr = vma->vm_start-len;
+ } while (len <= vma->vm_start);
+
+fail:
+ /*
+ * if hint left us with no space for the requested
+ * mapping then try again:
+ */
+ if (first_time) {
+ mm->free_area_cache = base;
+ first_time = 0;
+ goto try_again;
+ }
+ /*
+ * A failed mmap() very likely causes application failure,
+ * so fall back to the bottom-up function here. This scenario
+ * can happen with large stack limits and large mmap()
+ * allocations.
+ */
+ mm->free_area_cache = TASK_UNMAPPED_BASE;
+ addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
+ /*
+ * Restore the topdown base:
+ */
+ mm->free_area_cache = base;
+
+ return addr;
+}
+
+void arch_unmap_area_topdown(struct vm_area_struct *area)
+{
+ /*
+ * Is this a new hole at the highest possible address?
+ */
+ if (area->vm_end > area->vm_mm->free_area_cache)
+ area->vm_mm->free_area_cache = area->vm_end;
+}
+
unsigned long
get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
@@ -1102,7 +1206,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
return file->f_op->get_unmapped_area(file, addr, len,
pgoff, flags);
- return arch_get_unmapped_area(file, addr, len, pgoff, flags);
+ return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
}
EXPORT_SYMBOL(get_unmapped_area);
@@ -1392,13 +1496,7 @@ static void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area)
area->vm_mm->total_vm -= len >> PAGE_SHIFT;
if (area->vm_flags & VM_LOCKED)
area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
- /*
- * Is this a new hole at the lowest possible address?
- */
- if (area->vm_start >= TASK_UNMAPPED_BASE &&
- area->vm_start < area->vm_mm->free_area_cache)
- area->vm_mm->free_area_cache = area->vm_start;
-
+ area->vm_mm->unmap_area(area);
remove_vm_struct(area);
}
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 343998d46bb03..ab9fb2dfbece2 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -153,9 +153,11 @@ get_dirty_limits(struct writeback_state *wbs, long *pbackground, long *pdirty)
if (dirty_ratio < 5)
dirty_ratio = 5;
- background_ratio = dirty_background_ratio;
- if (background_ratio >= dirty_ratio)
- background_ratio = dirty_ratio / 2;
+ /*
+ * Keep the ratio between dirty_ratio and background_ratio roughly
+ * what the sysctls are after dirty_ratio has been scaled (above).
+ */
+ background_ratio = dirty_background_ratio * dirty_ratio/vm_dirty_ratio;
background = (background_ratio * total_pages) / 100;
dirty = (dirty_ratio * total_pages) / 100;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index a1e8501808a55..d156d5dab9d99 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -78,7 +78,7 @@ static void bad_page(const char *function, struct page *page)
function, current->comm, page);
printk(KERN_EMERG "flags:0x%08lx mapping:%p mapcount:%d count:%d\n",
(unsigned long)page->flags, page->mapping,
- (int)page->mapcount, page_count(page));
+ page_mapcount(page), page_count(page));
printk(KERN_EMERG "Backtrace:\n");
dump_stack();
printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n");
@@ -87,13 +87,11 @@ static void bad_page(const char *function, struct page *page)
1 << PG_lru |
1 << PG_active |
1 << PG_dirty |
- 1 << PG_maplock |
- 1 << PG_anon |
1 << PG_swapcache |
1 << PG_writeback);
set_page_count(page, 0);
+ reset_page_mapcount(page);
page->mapping = NULL;
- page->mapcount = 0;
}
#ifndef CONFIG_HUGETLB_PAGE
@@ -229,8 +227,6 @@ static inline void free_pages_check(const char *function, struct page *page)
1 << PG_active |
1 << PG_reclaim |
1 << PG_slab |
- 1 << PG_maplock |
- 1 << PG_anon |
1 << PG_swapcache |
1 << PG_writeback )))
bad_page(function, page);
@@ -279,6 +275,8 @@ void __free_pages_ok(struct page *page, unsigned int order)
LIST_HEAD(list);
int i;
+ arch_free_page(page, order);
+
mod_page_state(pgfree, 1 << order);
for (i = 0 ; i < (1 << order) ; ++i)
free_pages_check(__FUNCTION__, page + i);
@@ -350,8 +348,6 @@ static void prep_new_page(struct page *page, int order)
1 << PG_active |
1 << PG_dirty |
1 << PG_reclaim |
- 1 << PG_maplock |
- 1 << PG_anon |
1 << PG_swapcache |
1 << PG_writeback )))
bad_page(__FUNCTION__, page);
@@ -509,8 +505,12 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
struct per_cpu_pages *pcp;
unsigned long flags;
+ arch_free_page(page, 0);
+
kernel_map_pages(page, 1, 0);
inc_page_state(pgfree);
+ if (PageAnon(page))
+ page->mapping = NULL;
free_pages_check(__FUNCTION__, page);
pcp = &zone->pageset[get_cpu()].pcp[cold];
local_irq_save(flags);
@@ -600,83 +600,75 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order,
{
const int wait = gfp_mask & __GFP_WAIT;
unsigned long min;
- struct zone **zones;
+ struct zone **zones, *z;
struct page *page;
struct reclaim_state reclaim_state;
struct task_struct *p = current;
int i;
int alloc_type;
int do_retry;
+ int can_try_harder;
might_sleep_if(wait);
+ /*
+ * The caller may dip into page reserves a bit more if the caller
+ * cannot run direct reclaim, or is the caller has realtime scheduling
+ * policy
+ */
+ can_try_harder = (unlikely(rt_task(p)) && !in_interrupt()) || !wait;
+
zones = zonelist->zones; /* the list of zones suitable for gfp_mask */
- if (zones[0] == NULL) /* no zones in the zonelist */
+
+ if (unlikely(zones[0] == NULL)) {
+ /* Should this ever happen?? */
return NULL;
+ }
alloc_type = zone_idx(zones[0]);
/* Go through the zonelist once, looking for a zone with enough free */
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *z = zones[i];
-
- min = (1<<order) + z->protection[alloc_type];
+ for (i = 0; (z = zones[i]) != NULL; i++) {
+ min = z->pages_low + (1<<order) + z->protection[alloc_type];
- /*
- * We let real-time tasks dip their real-time paws a little
- * deeper into reserves.
- */
- if (rt_task(p))
- min -= z->pages_low >> 1;
+ if (z->free_pages < min)
+ continue;
- if (z->free_pages >= min ||
- (!wait && z->free_pages >= z->pages_high)) {
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page) {
- zone_statistics(zonelist, z);
- goto got_pg;
- }
- }
+ page = buffered_rmqueue(z, order, gfp_mask);
+ if (page)
+ goto got_pg;
}
- /* we're somewhat low on memory, failed to find what we needed */
- for (i = 0; zones[i] != NULL; i++)
- wakeup_kswapd(zones[i]);
-
- /* Go through the zonelist again, taking __GFP_HIGH into account */
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *z = zones[i];
-
- min = (1<<order) + z->protection[alloc_type];
+ for (i = 0; (z = zones[i]) != NULL; i++)
+ wakeup_kswapd(z);
+ /*
+ * Go through the zonelist again. Let __GFP_HIGH and allocations
+ * coming from realtime tasks to go deeper into reserves
+ */
+ for (i = 0; (z = zones[i]) != NULL; i++) {
+ min = z->pages_min;
if (gfp_mask & __GFP_HIGH)
- min -= z->pages_low >> 2;
- if (rt_task(p))
- min -= z->pages_low >> 1;
+ min /= 2;
+ if (can_try_harder)
+ min -= min / 4;
+ min += (1<<order) + z->protection[alloc_type];
- if (z->free_pages >= min ||
- (!wait && z->free_pages >= z->pages_high)) {
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page) {
- zone_statistics(zonelist, z);
- goto got_pg;
- }
- }
- }
+ if (z->free_pages < min)
+ continue;
- /* here we're in the low on memory slow path */
+ page = buffered_rmqueue(z, order, gfp_mask);
+ if (page)
+ goto got_pg;
+ }
-rebalance:
+ /* This allocation should allow future memory freeing. */
if ((p->flags & (PF_MEMALLOC | PF_MEMDIE)) && !in_interrupt()) {
/* go through the zonelist yet again, ignoring mins */
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *z = zones[i];
-
+ for (i = 0; (z = zones[i]) != NULL; i++) {
page = buffered_rmqueue(z, order, gfp_mask);
- if (page) {
- zone_statistics(zonelist, z);
+ if (page)
goto got_pg;
- }
}
goto nopage;
}
@@ -685,6 +677,8 @@ rebalance:
if (!wait)
goto nopage;
+rebalance:
+ /* We now go into synchronous reclaim */
p->flags |= PF_MEMALLOC;
reclaim_state.reclaimed_slab = 0;
p->reclaim_state = &reclaim_state;
@@ -695,27 +689,28 @@ rebalance:
p->flags &= ~PF_MEMALLOC;
/* go through the zonelist yet one more time */
- for (i = 0; zones[i] != NULL; i++) {
- struct zone *z = zones[i];
+ for (i = 0; (z = zones[i]) != NULL; i++) {
+ min = z->pages_min;
+ if (gfp_mask & __GFP_HIGH)
+ min /= 2;
+ if (can_try_harder)
+ min -= min / 4;
+ min += (1<<order) + z->protection[alloc_type];
- min = (1UL << order) + z->protection[alloc_type];
+ if (z->free_pages < min)
+ continue;
- if (z->free_pages >= min ||
- (!wait && z->free_pages >= z->pages_high)) {
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page) {
- zone_statistics(zonelist, z);
- goto got_pg;
- }
- }
+ page = buffered_rmqueue(z, order, gfp_mask);
+ if (page)
+ goto got_pg;
}
/*
* Don't let big-order allocations loop unless the caller explicitly
* requests that. Wait for some write requests to complete then retry.
*
- * In this implementation, __GFP_REPEAT means __GFP_NOFAIL, but that
- * may not be true in other implementations.
+ * In this implementation, __GFP_REPEAT means __GFP_NOFAIL for order
+ * <= 3, but that may not be true in other implementations.
*/
do_retry = 0;
if (!(gfp_mask & __GFP_NORETRY)) {
@@ -738,6 +733,7 @@ nopage:
}
return NULL;
got_pg:
+ zone_statistics(zonelist, z);
kernel_map_pages(page, 1 << order, 1);
return page;
}
@@ -965,18 +961,36 @@ unsigned long __read_page_state(unsigned offset)
return ret;
}
+void __get_zone_counts(unsigned long *active, unsigned long *inactive,
+ unsigned long *free, struct pglist_data *pgdat)
+{
+ struct zone *zones = pgdat->node_zones;
+ int i;
+
+ *active = 0;
+ *inactive = 0;
+ *free = 0;
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ *active += zones[i].nr_active;
+ *inactive += zones[i].nr_inactive;
+ *free += zones[i].free_pages;
+ }
+}
+
void get_zone_counts(unsigned long *active,
unsigned long *inactive, unsigned long *free)
{
- struct zone *zone;
+ struct pglist_data *pgdat;
*active = 0;
*inactive = 0;
*free = 0;
- for_each_zone(zone) {
- *active += zone->nr_active;
- *inactive += zone->nr_inactive;
- *free += zone->free_pages;
+ for_each_pgdat(pgdat) {
+ unsigned long l, m, n;
+ __get_zone_counts(&l, &m, &n, pgdat);
+ *active += l;
+ *inactive += m;
+ *free += n;
}
}
@@ -1379,14 +1393,16 @@ static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
* up by free_all_bootmem() once the early boot process is
* done. Non-atomic initialization, single-pass.
*/
-void __init memmap_init_zone(struct page *start, unsigned long size, int nid,
- unsigned long zone, unsigned long start_pfn)
+void __init memmap_init_zone(unsigned long size, int nid, unsigned long zone,
+ unsigned long start_pfn)
{
+ struct page *start = pfn_to_page(start_pfn);
struct page *page;
for (page = start; page < (start + size); page++) {
set_page_zone(page, NODEZONE(nid, zone));
set_page_count(page, 0);
+ reset_page_mapcount(page);
SetPageReserved(page);
INIT_LIST_HEAD(&page->lru);
#ifdef WANT_PAGE_VIRTUAL
@@ -1445,8 +1461,8 @@ void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone, unsigned
}
#ifndef __HAVE_ARCH_MEMMAP_INIT
-#define memmap_init(start, size, nid, zone, start_pfn) \
- memmap_init_zone((start), (size), (nid), (zone), (start_pfn))
+#define memmap_init(size, nid, zone, start_pfn) \
+ memmap_init_zone((size), (nid), (zone), (start_pfn))
#endif
/*
@@ -1461,7 +1477,6 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
unsigned long i, j;
const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1);
int cpu, nid = pgdat->node_id;
- struct page *lmem_map = pgdat->node_mem_map;
unsigned long zone_start_pfn = pgdat->node_start_pfn;
pgdat->nr_zones = 0;
@@ -1549,35 +1564,41 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
pgdat->nr_zones = j+1;
- zone->zone_mem_map = lmem_map;
+ zone->zone_mem_map = pfn_to_page(zone_start_pfn);
zone->zone_start_pfn = zone_start_pfn;
if ((zone_start_pfn) & (zone_required_alignment-1))
printk("BUG: wrong zone alignment, it will crash\n");
- memmap_init(lmem_map, size, nid, j, zone_start_pfn);
+ memmap_init(size, nid, j, zone_start_pfn);
zone_start_pfn += size;
- lmem_map += size;
zone_init_free_lists(pgdat, zone, zone->spanned_pages);
}
}
-void __init free_area_init_node(int nid, struct pglist_data *pgdat,
- struct page *node_mem_map, unsigned long *zones_size,
- unsigned long node_start_pfn, unsigned long *zholes_size)
+void __init node_alloc_mem_map(struct pglist_data *pgdat)
{
unsigned long size;
+ size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
+ pgdat->node_mem_map = alloc_bootmem_node(pgdat, size);
+#ifndef CONFIG_DISCONTIGMEM
+ mem_map = contig_page_data.node_mem_map;
+#endif
+}
+
+void __init free_area_init_node(int nid, struct pglist_data *pgdat,
+ unsigned long *zones_size, unsigned long node_start_pfn,
+ unsigned long *zholes_size)
+{
pgdat->node_id = nid;
pgdat->node_start_pfn = node_start_pfn;
calculate_zone_totalpages(pgdat, zones_size, zholes_size);
- if (!node_mem_map) {
- size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
- node_mem_map = alloc_bootmem_node(pgdat, size);
- }
- pgdat->node_mem_map = node_mem_map;
+
+ if (!pfn_to_page(node_start_pfn))
+ node_alloc_mem_map(pgdat);
free_area_init_core(pgdat, zones_size, zholes_size);
}
@@ -1590,9 +1611,8 @@ EXPORT_SYMBOL(contig_page_data);
void __init free_area_init(unsigned long *zones_size)
{
- free_area_init_node(0, &contig_page_data, NULL, zones_size,
+ free_area_init_node(0, &contig_page_data, zones_size,
__pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL);
- mem_map = contig_page_data.node_mem_map;
}
#endif
@@ -1851,11 +1871,11 @@ static void setup_per_zone_protection(void)
* We never protect zones that don't have memory
* in them (j>max_zone) or zones that aren't in
* the zonelists for a certain type of
- * allocation (j>i). We have to assign these to
- * zero because the lower zones take
+ * allocation (j>=i). We have to assign these
+ * to zero because the lower zones take
* contributions from the higher zones.
*/
- if (j > max_zone || j > i) {
+ if (j > max_zone || j >= i) {
zone->protection[i] = 0;
continue;
}
@@ -1864,7 +1884,6 @@ static void setup_per_zone_protection(void)
*/
zone->protection[i] = higherzone_val(zone,
max_zone, i);
- zone->protection[i] += zone->pages_low;
}
}
}
diff --git a/mm/readahead.c b/mm/readahead.c
index 3780d40b39ad9..a5e6906a01e03 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -28,16 +28,15 @@ struct backing_dev_info default_backing_dev_info = {
EXPORT_SYMBOL_GPL(default_backing_dev_info);
/*
- * Initialise a struct file's readahead state
+ * Initialise a struct file's readahead state. Assumes that the caller has
+ * memset *ra to zero.
*/
void
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
{
- memset(ra, 0, sizeof(*ra));
ra->ra_pages = mapping->backing_dev_info->ra_pages;
ra->average = ra->ra_pages / 2;
}
-EXPORT_SYMBOL(file_ra_state_init);
/*
* Return max readahead size for this inode in number-of-pages.
@@ -572,6 +571,6 @@ unsigned long max_sane_readahead(unsigned long nr)
unsigned long inactive;
unsigned long free;
- get_zone_counts(&active, &inactive, &free);
+ __get_zone_counts(&active, &inactive, &free, NODE_DATA(numa_node_id()));
return min(nr, (inactive + free) / 2);
}
diff --git a/mm/rmap.c b/mm/rmap.c
index 1cb3353daa16d..19c159bf3c983 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -18,9 +18,30 @@
*/
/*
- * Locking: see "Lock ordering" summary in filemap.c.
- * In swapout, page_map_lock is held on entry to page_referenced and
- * try_to_unmap, so they trylock for i_mmap_lock and page_table_lock.
+ * Lock ordering in mm:
+ *
+ * inode->i_sem (while writing or truncating, not reading or faulting)
+ * inode->i_alloc_sem
+ *
+ * When a page fault occurs in writing from user to file, down_read
+ * of mmap_sem nests within i_sem; in sys_msync, i_sem nests within
+ * down_read of mmap_sem; i_sem and down_write of mmap_sem are never
+ * taken together; in truncation, i_sem is taken outermost.
+ *
+ * mm->mmap_sem
+ * page->flags PG_locked (lock_page)
+ * mapping->i_mmap_lock
+ * anon_vma->lock
+ * mm->page_table_lock
+ * zone->lru_lock (in mark_page_accessed)
+ * swap_list_lock (in swap_free etc's swap_info_get)
+ * swap_device_lock (in swap_duplicate, swap_info_get)
+ * mapping->private_lock (in __set_page_dirty_buffers)
+ * inode_lock (in set_page_dirty's __mark_inode_dirty)
+ * sb_lock (within inode_lock in fs/fs-writeback.c)
+ * mapping->tree_lock (widely used, in set_page_dirty,
+ * in arch-dependent flush_dcache_mmap_lock,
+ * within inode_lock in __sync_single_inode)
*/
#include <linux/mm.h>
@@ -30,6 +51,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/rmap.h>
+#include <linux/rcupdate.h>
#include <asm/tlbflush.h>
@@ -63,28 +85,32 @@ int anon_vma_prepare(struct vm_area_struct *vma)
might_sleep();
if (unlikely(!anon_vma)) {
struct mm_struct *mm = vma->vm_mm;
- struct anon_vma *allocated = NULL;
+ struct anon_vma *allocated, *locked;
anon_vma = find_mergeable_anon_vma(vma);
- if (!anon_vma) {
+ if (anon_vma) {
+ allocated = NULL;
+ locked = anon_vma;
+ spin_lock(&locked->lock);
+ } else {
anon_vma = anon_vma_alloc();
if (unlikely(!anon_vma))
return -ENOMEM;
allocated = anon_vma;
+ locked = NULL;
}
/* page_table_lock to protect against threads */
spin_lock(&mm->page_table_lock);
if (likely(!vma->anon_vma)) {
- if (!allocated)
- spin_lock(&anon_vma->lock);
vma->anon_vma = anon_vma;
list_add(&vma->anon_vma_node, &anon_vma->head);
- if (!allocated)
- spin_unlock(&anon_vma->lock);
allocated = NULL;
}
spin_unlock(&mm->page_table_lock);
+
+ if (locked)
+ spin_unlock(&locked->lock);
if (unlikely(allocated))
anon_vma_free(allocated);
}
@@ -159,16 +185,31 @@ static void anon_vma_ctor(void *data, kmem_cache_t *cachep, unsigned long flags)
void __init anon_vma_init(void)
{
- anon_vma_cachep = kmem_cache_create("anon_vma",
- sizeof(struct anon_vma), 0, SLAB_PANIC, anon_vma_ctor, NULL);
+ anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma),
+ 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor, NULL);
}
-/* this needs the page->flags PG_maplock held */
-static inline void clear_page_anon(struct page *page)
+/*
+ * Getting a lock on a stable anon_vma from a page off the LRU is
+ * tricky: page_lock_anon_vma rely on RCU to guard against the races.
+ */
+static struct anon_vma *page_lock_anon_vma(struct page *page)
{
- BUG_ON(!page->mapping);
- page->mapping = NULL;
- ClearPageAnon(page);
+ struct anon_vma *anon_vma = NULL;
+ unsigned long anon_mapping;
+
+ rcu_read_lock();
+ anon_mapping = (unsigned long) page->mapping;
+ if (!(anon_mapping & PAGE_MAPPING_ANON))
+ goto out;
+ if (!page_mapped(page))
+ goto out;
+
+ anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
+ spin_lock(&anon_vma->lock);
+out:
+ rcu_read_unlock();
+ return anon_vma;
}
/*
@@ -190,6 +231,24 @@ vma_address(struct page *page, struct vm_area_struct *vma)
}
/*
+ * At what user virtual address is page expected in vma? checking that the
+ * page matches the vma: currently only used by unuse_process, on anon pages.
+ */
+unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
+{
+ if (PageAnon(page)) {
+ if ((void *)vma->anon_vma !=
+ (void *)page->mapping - PAGE_MAPPING_ANON)
+ return -EFAULT;
+ } else if (page->mapping && !(vma->vm_flags & VM_NONLINEAR)) {
+ if (vma->vm_file->f_mapping != page->mapping)
+ return -EFAULT;
+ } else
+ return -EFAULT;
+ return vma_address(page, vma);
+}
+
+/*
* Subfunctions of page_referenced: page_referenced_one called
* repeatedly from either page_referenced_anon or page_referenced_file.
*/
@@ -209,8 +268,7 @@ static int page_referenced_one(struct page *page,
if (address == -EFAULT)
goto out;
- if (!spin_trylock(&mm->page_table_lock))
- goto out;
+ spin_lock(&mm->page_table_lock);
pgd = pgd_offset(mm, address);
if (!pgd_present(*pgd))
@@ -243,15 +301,18 @@ out:
return referenced;
}
-static inline int page_referenced_anon(struct page *page)
+static int page_referenced_anon(struct page *page)
{
- unsigned int mapcount = page->mapcount;
- struct anon_vma *anon_vma = (struct anon_vma *) page->mapping;
+ unsigned int mapcount;
+ struct anon_vma *anon_vma;
struct vm_area_struct *vma;
int referenced = 0;
- spin_lock(&anon_vma->lock);
- BUG_ON(list_empty(&anon_vma->head));
+ anon_vma = page_lock_anon_vma(page);
+ if (!anon_vma)
+ return referenced;
+
+ mapcount = page_mapcount(page);
list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
referenced += page_referenced_one(page, vma, &mapcount);
if (!mapcount)
@@ -271,21 +332,38 @@ static inline int page_referenced_anon(struct page *page)
* of references it found.
*
* This function is only called from page_referenced for object-based pages.
- *
- * The spinlock address_space->i_mmap_lock is tried. If it can't be gotten,
- * assume a reference count of 0, so try_to_unmap will then have a go.
*/
-static inline int page_referenced_file(struct page *page)
+static int page_referenced_file(struct page *page)
{
- unsigned int mapcount = page->mapcount;
+ unsigned int mapcount;
struct address_space *mapping = page->mapping;
pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
struct vm_area_struct *vma;
struct prio_tree_iter iter;
int referenced = 0;
- if (!spin_trylock(&mapping->i_mmap_lock))
- return 0;
+ /*
+ * The caller's checks on page->mapping and !PageAnon have made
+ * sure that this is a file page: the check for page->mapping
+ * excludes the case just before it gets set on an anon page.
+ */
+ BUG_ON(PageAnon(page));
+
+ /*
+ * The page lock not only makes sure that page->mapping cannot
+ * suddenly be NULLified by truncation, it makes sure that the
+ * structure at mapping cannot be freed and reused yet,
+ * so we can safely take mapping->i_mmap_lock.
+ */
+ BUG_ON(!PageLocked(page));
+
+ spin_lock(&mapping->i_mmap_lock);
+
+ /*
+ * i_mmap_lock does not stabilize mapcount at all, but mapcount
+ * is more likely to be accurate if we note it after spinning.
+ */
+ mapcount = page_mapcount(page);
vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
if ((vma->vm_flags & (VM_LOCKED|VM_MAYSHARE))
@@ -305,12 +383,12 @@ static inline int page_referenced_file(struct page *page)
/**
* page_referenced - test if the page was referenced
* @page: the page to test
+ * @is_locked: caller holds lock on the page
*
* Quick test_and_clear_referenced for all mappings to a page,
* returns the number of ptes which referenced the page.
- * Caller needs to hold the rmap lock.
*/
-int page_referenced(struct page *page)
+int page_referenced(struct page *page, int is_locked)
{
int referenced = 0;
@@ -320,11 +398,17 @@ int page_referenced(struct page *page)
if (TestClearPageReferenced(page))
referenced++;
- if (page->mapcount && page->mapping) {
+ if (page_mapped(page) && page->mapping) {
if (PageAnon(page))
referenced += page_referenced_anon(page);
- else
+ else if (is_locked)
+ referenced += page_referenced_file(page);
+ else if (TestSetPageLocked(page))
+ referenced++;
+ else if (page->mapping) {
referenced += page_referenced_file(page);
+ unlock_page(page);
+ }
}
return referenced;
}
@@ -346,36 +430,17 @@ void page_add_anon_rmap(struct page *page,
BUG_ON(PageReserved(page));
BUG_ON(!anon_vma);
+ anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
index = (address - vma->vm_start) >> PAGE_SHIFT;
index += vma->vm_pgoff;
index >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
- /*
- * Setting and clearing PG_anon must always happen inside
- * page_map_lock to avoid races between mapping and
- * unmapping on different processes of the same
- * shared cow swapcache page. And while we take the
- * page_map_lock PG_anon cannot change from under us.
- * Actually PG_anon cannot change under fork either
- * since fork holds a reference on the page so it cannot
- * be unmapped under fork and in turn copy_page_range is
- * allowed to read PG_anon outside the page_map_lock.
- */
- page_map_lock(page);
- if (!page->mapcount) {
- BUG_ON(PageAnon(page));
- BUG_ON(page->mapping);
- SetPageAnon(page);
+ if (atomic_inc_and_test(&page->_mapcount)) {
page->index = index;
page->mapping = (struct address_space *) anon_vma;
inc_page_state(nr_mapped);
- } else {
- BUG_ON(!PageAnon(page));
- BUG_ON(page->index != index);
- BUG_ON(page->mapping != (struct address_space *) anon_vma);
}
- page->mapcount++;
- page_map_unlock(page);
+ /* else checking page index and mapping is racy */
}
/**
@@ -390,11 +455,8 @@ void page_add_file_rmap(struct page *page)
if (!pfn_valid(page_to_pfn(page)) || PageReserved(page))
return;
- page_map_lock(page);
- if (!page->mapcount)
+ if (atomic_inc_and_test(&page->_mapcount))
inc_page_state(nr_mapped);
- page->mapcount++;
- page_map_unlock(page);
}
/**
@@ -406,18 +468,22 @@ void page_add_file_rmap(struct page *page)
void page_remove_rmap(struct page *page)
{
BUG_ON(PageReserved(page));
- BUG_ON(!page->mapcount);
- page_map_lock(page);
- page->mapcount--;
- if (!page->mapcount) {
+ if (atomic_add_negative(-1, &page->_mapcount)) {
+ BUG_ON(page_mapcount(page) < 0);
+ /*
+ * It would be tidy to reset the PageAnon mapping here,
+ * but that might overwrite a racing page_add_anon_rmap
+ * which increments mapcount after us but sets mapping
+ * before us: so leave the reset to free_hot_cold_page,
+ * and remember that it's only reliable while mapped.
+ * Leaving it set also helps swapoff to reinstate ptes
+ * faster for those pages still in swapcache.
+ */
if (page_test_and_clear_dirty(page))
set_page_dirty(page);
- if (PageAnon(page))
- clear_page_anon(page);
dec_page_state(nr_mapped);
}
- page_map_unlock(page);
}
/*
@@ -444,8 +510,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
* We need the page_table_lock to protect us from page faults,
* munmap, fork, etc...
*/
- if (!spin_trylock(&mm->page_table_lock))
- goto out;
+ spin_lock(&mm->page_table_lock);
pgd = pgd_offset(mm, address);
if (!pgd_present(*pgd))
@@ -489,7 +554,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
* ptes from being unmapped, so swapoff can make progress.
*/
if (PageSwapCache(page) &&
- page_count(page) != page->mapcount + 2) {
+ page_count(page) != page_mapcount(page) + 2) {
ret = SWAP_FAIL;
goto out_unmap;
}
@@ -515,8 +580,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
}
mm->rss--;
- BUG_ON(!page->mapcount);
- page->mapcount--;
+ page_remove_rmap(page);
page_cache_release(page);
out_unmap:
@@ -549,7 +613,7 @@ out:
#define CLUSTER_SIZE min(32*PAGE_SIZE, PMD_SIZE)
#define CLUSTER_MASK (~(CLUSTER_SIZE - 1))
-static int try_to_unmap_cluster(unsigned long cursor,
+static void try_to_unmap_cluster(unsigned long cursor,
unsigned int *mapcount, struct vm_area_struct *vma)
{
struct mm_struct *mm = vma->vm_mm;
@@ -566,8 +630,7 @@ static int try_to_unmap_cluster(unsigned long cursor,
* We need the page_table_lock to protect us from page faults,
* munmap, fork, etc...
*/
- if (!spin_trylock(&mm->page_table_lock))
- return SWAP_FAIL;
+ spin_lock(&mm->page_table_lock);
address = (vma->vm_start + cursor) & CLUSTER_MASK;
end = address + CLUSTER_SIZE;
@@ -624,20 +687,21 @@ static int try_to_unmap_cluster(unsigned long cursor,
out_unlock:
spin_unlock(&mm->page_table_lock);
- return SWAP_AGAIN;
}
-static inline int try_to_unmap_anon(struct page *page)
+static int try_to_unmap_anon(struct page *page)
{
- struct anon_vma *anon_vma = (struct anon_vma *) page->mapping;
+ struct anon_vma *anon_vma;
struct vm_area_struct *vma;
int ret = SWAP_AGAIN;
- spin_lock(&anon_vma->lock);
- BUG_ON(list_empty(&anon_vma->head));
+ anon_vma = page_lock_anon_vma(page);
+ if (!anon_vma)
+ return ret;
+
list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
ret = try_to_unmap_one(page, vma);
- if (ret == SWAP_FAIL || !page->mapcount)
+ if (ret == SWAP_FAIL || !page_mapped(page))
break;
}
spin_unlock(&anon_vma->lock);
@@ -652,11 +716,8 @@ static inline int try_to_unmap_anon(struct page *page)
* contained in the address_space struct it points to.
*
* This function is only called from try_to_unmap for object-based pages.
- *
- * The spinlock address_space->i_mmap_lock is tried. If it can't be gotten,
- * return a temporary error.
*/
-static inline int try_to_unmap_file(struct page *page)
+static int try_to_unmap_file(struct page *page)
{
struct address_space *mapping = page->mapping;
pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
@@ -668,12 +729,10 @@ static inline int try_to_unmap_file(struct page *page)
unsigned long max_nl_size = 0;
unsigned int mapcount;
- if (!spin_trylock(&mapping->i_mmap_lock))
- return ret;
-
+ spin_lock(&mapping->i_mmap_lock);
vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
ret = try_to_unmap_one(page, vma);
- if (ret == SWAP_FAIL || !page->mapcount)
+ if (ret == SWAP_FAIL || !page_mapped(page))
goto out;
}
@@ -692,8 +751,10 @@ static inline int try_to_unmap_file(struct page *page)
max_nl_size = cursor;
}
- if (max_nl_size == 0) /* any nonlinears locked or reserved */
+ if (max_nl_size == 0) { /* any nonlinears locked or reserved */
+ ret = SWAP_FAIL;
goto out;
+ }
/*
* We don't try to search for this page in the nonlinear vmas,
@@ -702,8 +763,9 @@ static inline int try_to_unmap_file(struct page *page)
* The mapcount of the page we came in with is irrelevant,
* but even so use it as a guide to how hard we should try?
*/
- mapcount = page->mapcount;
- page_map_unlock(page);
+ mapcount = page_mapcount(page);
+ if (!mapcount)
+ goto out;
cond_resched_lock(&mapping->i_mmap_lock);
max_nl_size = (max_nl_size + CLUSTER_SIZE - 1) & CLUSTER_MASK;
@@ -719,19 +781,13 @@ static inline int try_to_unmap_file(struct page *page)
while (vma->vm_mm->rss &&
cursor < max_nl_cursor &&
cursor < vma->vm_end - vma->vm_start) {
- ret = try_to_unmap_cluster(
- cursor, &mapcount, vma);
- if (ret == SWAP_FAIL)
- break;
+ try_to_unmap_cluster(cursor, &mapcount, vma);
cursor += CLUSTER_SIZE;
vma->vm_private_data = (void *) cursor;
if ((int)mapcount <= 0)
- goto relock;
+ goto out;
}
- if (ret != SWAP_FAIL)
- vma->vm_private_data =
- (void *) max_nl_cursor;
- ret = SWAP_AGAIN;
+ vma->vm_private_data = (void *) max_nl_cursor;
}
cond_resched_lock(&mapping->i_mmap_lock);
max_nl_cursor += CLUSTER_SIZE;
@@ -747,8 +803,6 @@ static inline int try_to_unmap_file(struct page *page)
if (!(vma->vm_flags & VM_RESERVED))
vma->vm_private_data = NULL;
}
-relock:
- page_map_lock(page);
out:
spin_unlock(&mapping->i_mmap_lock);
return ret;
@@ -759,11 +813,11 @@ out:
* @page: the page to get unmapped
*
* Tries to remove all the page table entries which are mapping this
- * page, used in the pageout path. Caller must hold the page lock
- * and its rmap lock. Return values are:
+ * page, used in the pageout path. Caller must hold the page lock.
+ * Return values are:
*
* SWAP_SUCCESS - we succeeded in removing all mappings
- * SWAP_AGAIN - we missed a trylock, try again later
+ * SWAP_AGAIN - we missed a mapping, try again later
* SWAP_FAIL - the page is unswappable
*/
int try_to_unmap(struct page *page)
@@ -772,20 +826,13 @@ int try_to_unmap(struct page *page)
BUG_ON(PageReserved(page));
BUG_ON(!PageLocked(page));
- BUG_ON(!page->mapcount);
if (PageAnon(page))
ret = try_to_unmap_anon(page);
else
ret = try_to_unmap_file(page);
- if (!page->mapcount) {
- if (page_test_and_clear_dirty(page))
- set_page_dirty(page);
- if (PageAnon(page))
- clear_page_anon(page);
- dec_page_state(nr_mapped);
+ if (!page_mapped(page))
ret = SWAP_SUCCESS;
- }
return ret;
}
diff --git a/mm/slab.c b/mm/slab.c
index fd80d31fbab0a..887bec4dde632 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -91,6 +91,7 @@
#include <linux/cpu.h>
#include <linux/sysctl.h>
#include <linux/module.h>
+#include <linux/rcupdate.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -139,11 +140,13 @@
SLAB_POISON | SLAB_HWCACHE_ALIGN | \
SLAB_NO_REAP | SLAB_CACHE_DMA | \
SLAB_MUST_HWCACHE_ALIGN | SLAB_STORE_USER | \
- SLAB_RECLAIM_ACCOUNT | SLAB_PANIC)
+ SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
+ SLAB_DESTROY_BY_RCU)
#else
# define CREATE_MASK (SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | \
SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN | \
- SLAB_RECLAIM_ACCOUNT | SLAB_PANIC)
+ SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
+ SLAB_DESTROY_BY_RCU)
#endif
/*
@@ -190,6 +193,28 @@ struct slab {
};
/*
+ * struct slab_rcu
+ *
+ * slab_destroy on a SLAB_DESTROY_BY_RCU cache uses this structure to
+ * arrange for kmem_freepages to be called via RCU. This is useful if
+ * we need to approach a kernel structure obliquely, from its address
+ * obtained without the usual locking. We can lock the structure to
+ * stabilize it and check it's still at the given address, only if we
+ * can be sure that the memory has not been meanwhile reused for some
+ * other kind of object (which our subsystem's lock might corrupt).
+ *
+ * rcu_read_lock before reading the address, then rcu_read_unlock after
+ * taking the spinlock within the structure expected at that address.
+ *
+ * We assume struct slab_rcu can overlay struct slab when destroying.
+ */
+struct slab_rcu {
+ struct rcu_head head;
+ kmem_cache_t *cachep;
+ void *addr;
+};
+
+/*
* struct array_cache
*
* Per cpu structures
@@ -873,6 +898,16 @@ static void kmem_freepages(kmem_cache_t *cachep, void *addr)
atomic_sub(1<<cachep->gfporder, &slab_reclaim_pages);
}
+static void kmem_rcu_free(struct rcu_head *head)
+{
+ struct slab_rcu *slab_rcu = (struct slab_rcu *) head;
+ kmem_cache_t *cachep = slab_rcu->cachep;
+
+ kmem_freepages(cachep, slab_rcu->addr);
+ if (OFF_SLAB(cachep))
+ kmem_cache_free(cachep->slabp_cache, slab_rcu);
+}
+
#if DEBUG
#ifdef CONFIG_DEBUG_PAGEALLOC
@@ -1026,6 +1061,8 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp)
*/
static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
{
+ void *addr = slabp->s_mem - slabp->colouroff;
+
#if DEBUG
int i;
for (i = 0; i < cachep->num; i++) {
@@ -1061,10 +1098,19 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
}
}
#endif
-
- kmem_freepages(cachep, slabp->s_mem-slabp->colouroff);
- if (OFF_SLAB(cachep))
- kmem_cache_free(cachep->slabp_cache, slabp);
+
+ if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) {
+ struct slab_rcu *slab_rcu;
+
+ slab_rcu = (struct slab_rcu *) slabp;
+ slab_rcu->cachep = cachep;
+ slab_rcu->addr = addr;
+ call_rcu(&slab_rcu->head, kmem_rcu_free);
+ } else {
+ kmem_freepages(cachep, addr);
+ if (OFF_SLAB(cachep))
+ kmem_cache_free(cachep->slabp_cache, slabp);
+ }
}
/**
@@ -1139,9 +1185,15 @@ kmem_cache_create (const char *name, size_t size, size_t align,
*/
if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD)))
flags |= SLAB_RED_ZONE|SLAB_STORE_USER;
- flags |= SLAB_POISON;
+ if (!(flags & SLAB_DESTROY_BY_RCU))
+ flags |= SLAB_POISON;
#endif
+ if (flags & SLAB_DESTROY_BY_RCU)
+ BUG_ON(flags & SLAB_POISON);
#endif
+ if (flags & SLAB_DESTROY_BY_RCU)
+ BUG_ON(dtor);
+
/*
* Always checks flags, a caller might be expecting debug
* support which isn't available.
@@ -1553,6 +1605,9 @@ int kmem_cache_destroy (kmem_cache_t * cachep)
return 1;
}
+ if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
+ synchronize_kernel();
+
/* no cpu_online check required here since we clear the percpu
* array on cpu offline and set this to NULL.
*/
diff --git a/mm/swapfile.c b/mm/swapfile.c
index a523ca237636d..b7ecb1bb20149 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -520,14 +520,24 @@ static unsigned long unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
}
/* vma->vm_mm->page_table_lock is held */
-static unsigned long unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
+static unsigned long unuse_vma(struct vm_area_struct * vma,
swp_entry_t entry, struct page *page)
{
- unsigned long start = vma->vm_start, end = vma->vm_end;
+ pgd_t *pgdir;
+ unsigned long start, end;
unsigned long foundaddr;
- if (start >= end)
- BUG();
+ if (page->mapping) {
+ start = page_address_in_vma(page, vma);
+ if (start == -EFAULT)
+ return 0;
+ else
+ end = start + PAGE_SIZE;
+ } else {
+ start = vma->vm_start;
+ end = vma->vm_end;
+ }
+ pgdir = pgd_offset(vma->vm_mm, start);
do {
foundaddr = unuse_pgd(vma, pgdir, start, end - start,
entry, page);
@@ -559,9 +569,8 @@ static int unuse_process(struct mm_struct * mm,
}
spin_lock(&mm->page_table_lock);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if (!is_vm_hugetlb_page(vma)) {
- pgd_t * pgd = pgd_offset(mm, vma->vm_start);
- foundaddr = unuse_vma(vma, pgd, entry, page);
+ if (vma->anon_vma) {
+ foundaddr = unuse_vma(vma, entry, page);
if (foundaddr)
break;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index b6660ec4226fd..501ef742e59e8 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -219,7 +219,7 @@ static int shrink_slab(unsigned long scanned, unsigned int gfp_mask,
return 0;
}
-/* Must be called with page's rmap lock held. */
+/* Called without lock on whether page is mapped, so answer is unstable */
static inline int page_mapping_inuse(struct page *page)
{
struct address_space *mapping;
@@ -377,26 +377,19 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc)
if (page_mapped(page) || PageSwapCache(page))
sc->nr_scanned++;
- page_map_lock(page);
- referenced = page_referenced(page);
- if (referenced && page_mapping_inuse(page)) {
- /* In active use or really unfreeable. Activate it. */
- page_map_unlock(page);
+ referenced = page_referenced(page, 1);
+ /* In active use or really unfreeable? Activate it. */
+ if (referenced && page_mapping_inuse(page))
goto activate_locked;
- }
#ifdef CONFIG_SWAP
/*
* Anonymous process memory has backing store?
* Try to allocate it some swap space here.
- *
- * XXX: implement swap clustering ?
*/
if (PageAnon(page) && !PageSwapCache(page)) {
- page_map_unlock(page);
if (!add_to_swap(page))
goto activate_locked;
- page_map_lock(page);
}
#endif /* CONFIG_SWAP */
@@ -411,16 +404,13 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc)
if (page_mapped(page) && mapping) {
switch (try_to_unmap(page)) {
case SWAP_FAIL:
- page_map_unlock(page);
goto activate_locked;
case SWAP_AGAIN:
- page_map_unlock(page);
goto keep_locked;
case SWAP_SUCCESS:
; /* try to free the page below */
}
}
- page_map_unlock(page);
if (PageDirty(page)) {
if (referenced)
@@ -723,25 +713,12 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc)
page = lru_to_page(&l_hold);
list_del(&page->lru);
if (page_mapped(page)) {
- if (!reclaim_mapped) {
- list_add(&page->lru, &l_active);
- continue;
- }
- page_map_lock(page);
- if (page_referenced(page)) {
- page_map_unlock(page);
+ if (!reclaim_mapped ||
+ (total_swap_pages == 0 && PageAnon(page)) ||
+ page_referenced(page, 0)) {
list_add(&page->lru, &l_active);
continue;
}
- page_map_unlock(page);
- }
- /*
- * FIXME: need to consider page_count(page) here if/when we
- * reap orphaned pages via the LRU (Daniel's locking stuff)
- */
- if (total_swap_pages == 0 && PageAnon(page)) {
- list_add(&page->lru, &l_active);
- continue;
}
list_add(&page->lru, &l_inactive);
}
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
index 4f1849f9ab29a..60834b5a14d60 100644
--- a/net/atm/mpoa_proc.c
+++ b/net/atm/mpoa_proc.c
@@ -121,7 +121,7 @@ static void mpc_stop(struct seq_file *m, void *v)
/*
* READING function - called when the /proc/atm/mpoa file is read from.
*/
-static ssize_t mpc_show(struct seq_file *m, void *v)
+static int mpc_show(struct seq_file *m, void *v)
{
struct mpoa_client *mpc = v;
unsigned char *temp;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 8a9f66335f95b..d18d7b8ba1e26 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -45,26 +45,15 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
br_pass_frame_up_finish);
}
+/* note: already called with rcu_read_lock (preempt_disabled) */
int br_handle_frame_finish(struct sk_buff *skb)
{
- struct net_bridge *br;
- unsigned char *dest;
+ const unsigned char *dest = skb->mac.ethernet->h_dest;
+ struct net_bridge_port *p = skb->dev->br_port;
+ struct net_bridge *br = p->br;
struct net_bridge_fdb_entry *dst;
- struct net_bridge_port *p;
- int passedup;
+ int passedup = 0;
- dest = skb->mac.ethernet->h_dest;
-
- rcu_read_lock();
- p = rcu_dereference(skb->dev->br_port);
-
- if (p == NULL || p->state == BR_STATE_DISABLED) {
- kfree_skb(skb);
- goto out;
- }
-
- br = p->br;
- passedup = 0;
if (br->dev->flags & IFF_PROMISC) {
struct sk_buff *skb2;
@@ -99,20 +88,21 @@ int br_handle_frame_finish(struct sk_buff *skb)
br_flood_forward(br, skb, 0);
out:
- rcu_read_unlock();
return 0;
}
-int br_handle_frame(struct sk_buff *skb)
+/*
+ * Called via br_handle_frame_hook.
+ * Return 0 if *pskb should be processed furthur
+ * 1 if *pskb is handled
+ * note: already called with rcu_read_lock (preempt_disabled)
+ */
+int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)
{
- unsigned char *dest;
- struct net_bridge_port *p;
+ struct sk_buff *skb = *pskb;
+ const unsigned char *dest = skb->mac.ethernet->h_dest;
- dest = skb->mac.ethernet->h_dest;
-
- rcu_read_lock();
- p = skb->dev->br_port;
- if (p == NULL || p->state == BR_STATE_DISABLED)
+ if (p->state == BR_STATE_DISABLED)
goto err;
if (skb->mac.ethernet->h_source[0] & 1)
@@ -128,15 +118,16 @@ int br_handle_frame(struct sk_buff *skb)
if (!dest[5]) {
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
NULL, br_stp_handle_bpdu);
- rcu_read_unlock();
- return 0;
+ return 1;
}
}
else if (p->state == BR_STATE_FORWARDING) {
- if (br_should_route_hook && br_should_route_hook(&skb)) {
- rcu_read_unlock();
- return -1;
+ if (br_should_route_hook) {
+ if (br_should_route_hook(pskb))
+ return 0;
+ skb = *pskb;
+ dest = skb->mac.ethernet->h_dest;
}
if (!memcmp(p->br->dev->dev_addr, dest, ETH_ALEN))
@@ -144,12 +135,10 @@ int br_handle_frame(struct sk_buff *skb)
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
- rcu_read_unlock();
- return 0;
+ return 1;
}
err:
- rcu_read_unlock();
kfree_skb(skb);
- return 0;
+ return 1;
}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index d2b2fb27ffc56..cecdba777dd9e 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -177,7 +177,7 @@ extern int br_min_mtu(const struct net_bridge *br);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
-extern int br_handle_frame(struct sk_buff *skb);
+extern int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb);
/* br_ioctl.c */
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/core/dev.c b/net/core/dev.c
index da7fabc7aa26a..bd1f159be6505 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1144,16 +1144,10 @@ int skb_checksum_help(struct sk_buff **pskb, int inward)
goto out;
}
- if (skb_shared(*pskb) || skb_cloned(*pskb)) {
- struct sk_buff *newskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!newskb) {
- ret = -ENOMEM;
+ if (skb_cloned(*pskb)) {
+ ret = pskb_expand_head(*pskb, 0, 0, GFP_ATOMIC);
+ if (ret)
goto out;
- }
- if ((*pskb)->sk)
- skb_set_owner_w(newskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = newskb;
}
if (offset > (int)(*pskb)->len)
@@ -1676,43 +1670,34 @@ static void net_tx_action(struct softirq_action *h)
}
static __inline__ int deliver_skb(struct sk_buff *skb,
- struct packet_type *pt_prev, int last)
+ struct packet_type *pt_prev)
{
atomic_inc(&skb->users);
return pt_prev->func(skb, skb->dev, pt_prev);
}
-
#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-int (*br_handle_frame_hook)(struct sk_buff *skb);
+int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
-static __inline__ int handle_bridge(struct sk_buff *skb,
- struct packet_type *pt_prev)
+static __inline__ int handle_bridge(struct sk_buff **pskb,
+ struct packet_type **pt_prev, int *ret)
{
- int ret = NET_RX_DROP;
- if (pt_prev)
- ret = deliver_skb(skb, pt_prev, 0);
-
- return ret;
-}
+ struct net_bridge_port *port;
-#endif
-
-static inline int __handle_bridge(struct sk_buff *skb,
- struct packet_type **pt_prev, int *ret)
-{
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
- if (skb->dev->br_port && skb->pkt_type != PACKET_LOOPBACK) {
- *ret = handle_bridge(skb, *pt_prev);
- if (br_handle_frame_hook(skb) == 0)
- return 1;
+ if ((*pskb)->pkt_type == PACKET_LOOPBACK ||
+ (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
+ return 0;
+ if (*pt_prev) {
+ *ret = deliver_skb(*pskb, *pt_prev);
*pt_prev = NULL;
- }
-#endif
- return 0;
+ }
+
+ return br_handle_frame_hook(port, pskb);
}
-
+#else
+#define handle_bridge(skb, pt_prev, ret) (0)
+#endif
#ifdef CONFIG_NET_CLS_ACT
/* TODO: Maybe we should just force sch_ingress to be compiled in
@@ -1779,27 +1764,27 @@ int netif_receive_skb(struct sk_buff *skb)
skb->mac_len = skb->nh.raw - skb->mac.raw;
pt_prev = NULL;
+
+ rcu_read_lock();
+
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS) {
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
- rcu_read_lock();
goto ncls;
}
- #endif
+#endif
- rcu_read_lock();
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev)
- ret = deliver_skb(skb, pt_prev, 0);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = ptype;
}
}
#ifdef CONFIG_NET_CLS_ACT
if (pt_prev) {
- atomic_inc(&skb->users);
- ret = pt_prev->func(skb, skb->dev, pt_prev);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = NULL; /* noone else should process this after*/
} else {
skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);
@@ -1818,7 +1803,7 @@ ncls:
handle_diverter(skb);
- if (__handle_bridge(skb, &pt_prev, &ret))
+ if (handle_bridge(&skb, &pt_prev, &ret))
goto out;
type = skb->protocol;
@@ -1826,7 +1811,7 @@ ncls:
if (ptype->type == type &&
(!ptype->dev || ptype->dev == skb->dev)) {
if (pt_prev)
- ret = deliver_skb(skb, pt_prev, 0);
+ ret = deliver_skb(skb, pt_prev);
pt_prev = ptype;
}
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e0b5e89c863de..4b50fabc39c57 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -166,31 +166,53 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
r->ifi_family = AF_UNSPEC;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
- r->ifi_flags = dev->flags;
+ r->ifi_flags = dev_get_flags(dev);
r->ifi_change = change;
- if (!netif_running(dev) || !netif_carrier_ok(dev))
- r->ifi_flags &= ~IFF_RUNNING;
- else
- r->ifi_flags |= IFF_RUNNING;
-
RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
+
+ if (1) {
+ u32 txqlen = dev->tx_queue_len;
+ RTA_PUT(skb, IFLA_TXQLEN, sizeof(txqlen), &txqlen);
+ }
+
+ if (1) {
+ struct ifmap map = {
+ .mem_start = dev->mem_start,
+ .mem_end = dev->mem_end,
+ .base_addr = dev->base_addr,
+ .irq = dev->irq,
+ .dma = dev->dma,
+ .port = dev->if_port,
+ };
+ RTA_PUT(skb, IFLA_MAP, sizeof(map), &map);
+ }
+
if (dev->addr_len) {
RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
}
+
if (1) {
- unsigned mtu = dev->mtu;
+ u32 mtu = dev->mtu;
RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu);
}
- if (dev->ifindex != dev->iflink)
- RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink);
+
+ if (dev->ifindex != dev->iflink) {
+ u32 iflink = dev->iflink;
+ RTA_PUT(skb, IFLA_LINK, sizeof(iflink), &iflink);
+ }
+
if (dev->qdisc_sleeping)
RTA_PUT(skb, IFLA_QDISC,
strlen(dev->qdisc_sleeping->ops->id) + 1,
dev->qdisc_sleeping->ops->id);
- if (dev->master)
- RTA_PUT(skb, IFLA_MASTER, sizeof(int), &dev->master->ifindex);
+
+ if (dev->master) {
+ u32 master = dev->master->ifindex;
+ RTA_PUT(skb, IFLA_MASTER, sizeof(master), &master);
+ }
+
if (dev->get_stats) {
unsigned long *stats = (unsigned long*)dev->get_stats(dev);
if (stats) {
@@ -246,6 +268,30 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
err = -EINVAL;
+ if (ifm->ifi_flags)
+ dev_change_flags(dev, ifm->ifi_flags);
+
+ if (ida[IFLA_MAP - 1]) {
+ if (!dev->set_config) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!netif_device_present(dev)) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(struct ifmap)))
+ goto out;
+
+ err = dev->set_config(dev, (struct ifmap *)
+ RTA_DATA(ida[IFLA_MAP - 1]));
+
+ if (err)
+ goto out;
+ }
+
if (ida[IFLA_ADDRESS - 1]) {
if (!dev->set_mac_address) {
err = -EOPNOTSUPP;
@@ -270,6 +316,23 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
dev->addr_len);
}
+ if (ida[IFLA_MTU - 1]) {
+ if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
+ goto out;
+ err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1])));
+
+ if (err)
+ goto out;
+
+ }
+
+ if (ida[IFLA_TXQLEN - 1]) {
+ if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
+ goto out;
+
+ dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1]));
+ }
+
err = 0;
out:
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index b2f0dee33f2ab..b14c45f1716ae 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -15,6 +15,7 @@
#include <net/ip.h>
#include <net/checksum.h>
#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
index 8296e7c52cf88..64755c5aed6e6 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -66,7 +66,7 @@ unsigned long ip_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000;
unsigned long ip_ct_sctp_timeout_shutdown_ack_sent = 3 SECS;
static unsigned long * sctp_timeouts[]
-= { 0, /* SCTP_CONNTRACK_NONE */
+= { NULL, /* SCTP_CONNTRACK_NONE */
&ip_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */
&ip_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */
&ip_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 64c7538c4b185..1f5261d1f9ba9 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -33,6 +33,7 @@
#include <net/tcp.h>
#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/lockhelp.h>
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
index 0fe9e9188fdf2..4898b38560ab6 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
@@ -14,6 +14,7 @@
#include <linux/udp.h>
#include <net/checksum.h>
#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
unsigned long ip_ct_udp_timeout = 30*HZ;
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index d350134dacb1b..b10d35198d1e8 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -635,7 +635,7 @@ ip_nat_setup_info(struct ip_conntrack *conntrack,
/* If there's a helper, assign it; based on new tuple. */
if (!conntrack->master)
- info->helper = ip_nat_find_helper(&reply);
+ info->helper = __ip_nat_find_helper(&reply);
/* It's done. */
info->initialized |= (1 << HOOK2MANIP(hooknum));
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
index 2e8d021aff444..ede6757e54015 100644
--- a/net/ipv4/netfilter/ip_nat_helper.c
+++ b/net/ipv4/netfilter/ip_nat_helper.c
@@ -421,12 +421,18 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
}
struct ip_nat_helper *
+__ip_nat_find_helper(const struct ip_conntrack_tuple *tuple)
+{
+ return LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, tuple);
+}
+
+struct ip_nat_helper *
ip_nat_find_helper(const struct ip_conntrack_tuple *tuple)
{
struct ip_nat_helper *h;
READ_LOCK(&ip_nat_lock);
- h = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, tuple);
+ h = __ip_nat_find_helper(tuple);
READ_UNLOCK(&ip_nat_lock);
return h;
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 62ef0d1f7554d..fcc74c0facfe2 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -394,4 +394,6 @@ EXPORT_SYMBOL(ip_nat_cheat_check);
EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
EXPORT_SYMBOL(ip_nat_used_tuple);
+EXPORT_SYMBOL(ip_nat_find_helper);
+EXPORT_SYMBOL(__ip_nat_find_helper);
MODULE_LICENSE("GPL");
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 1bf740e71c647..21832dfc376eb 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -58,8 +58,7 @@ static void xfrm4_encap(struct sk_buff *skb)
if (!top_iph->frag_off)
__ip_select_ident(top_iph, dst, 0);
- /* TTL disclosed */
- top_iph->ttl = iph->ttl;
+ top_iph->ttl = dst_path_metric(dst, RTAX_HOPLIMIT);
top_iph->saddr = x->props.saddr.a4;
top_iph->daddr = x->id.daddr.a4;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 77e9de707e960..8caef0ce9ae60 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -820,9 +820,12 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
*/
if ((rtmsg->rtmsg_flags&RTF_REJECT) ||
(dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
- if (dev && dev != &loopback_dev) {
- dev_put(dev);
- in6_dev_put(idev);
+ /* hold loopback dev/idev if we haven't done so. */
+ if (dev != &loopback_dev) {
+ if (dev) {
+ dev_put(dev);
+ in6_dev_put(idev);
+ }
dev = &loopback_dev;
dev_hold(dev);
idev = in6_dev_get(dev);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 786de7d912bb0..b67187525d3c7 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -64,7 +64,7 @@ static void xfrm6_encap(struct sk_buff *skb)
top_iph->flow_lbl[1] = iph->flow_lbl[1];
top_iph->flow_lbl[2] = iph->flow_lbl[2];
top_iph->nexthdr = IPPROTO_IPV6;
- top_iph->hop_limit = iph->hop_limit;
+ top_iph->hop_limit = dst_path_metric(dst, RTAX_HOPLIMIT);
ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
}
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index 289ed358b7e5d..25339868d4621 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -126,7 +126,7 @@ spkm3_make_token(struct spkm3_ctx *ctx, int qop_req,
out_err:
if (md5cksum.data)
kfree(md5cksum.data);
- token->data = 0;
+ token->data = NULL;
token->len = 0;
return GSS_S_FAILURE;
}
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 9c03a6673aad6..8c4c703958cd8 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -93,6 +93,14 @@
* (Note: it'd be easy to port over the complete mkdep state machine,
* but I don't think the added complexity is worth it)
*/
+/*
+ * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
+ * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
+ * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
+ * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
+ * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
+ * those files will have correct dependencies.
+ */
#include <sys/types.h>
#include <sys/stat.h>
@@ -310,6 +318,7 @@ void parse_dep_file(void *map, size_t len)
}
memcpy(s, m, p-m); s[p-m] = 0;
if (strrcmp(s, "include/linux/autoconf.h") &&
+ strrcmp(s, "arch/um/include/uml-config.h") &&
strrcmp(s, ".ver")) {
printf(" %s \\\n", s);
do_config_file(s);
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index 631430d09e4de..b41b718edffef 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -1,4 +1,4 @@
-#include <arpa/inet.h>
+#include <netinet/in.h>
#include <stdint.h>
#include <ctype.h>
#include <errno.h>
diff --git a/security/Kconfig b/security/Kconfig
index d6bc0831731df..ddde53ba62345 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -26,14 +26,14 @@ config SECURITY_NETWORK
config SECURITY_CAPABILITIES
tristate "Default Linux Capabilities"
- depends on SECURITY!=n
+ depends on SECURITY
help
This enables the "default" Linux capabilities functionality.
If you are unsure how to answer this question, answer Y.
config SECURITY_ROOTPLUG
tristate "Root Plug Support"
- depends on USB && SECURITY!=n
+ depends on USB && SECURITY
help
This is a sample LSM module that should only be used as such.
It prevents any programs running with egid == 0 if a specific
diff --git a/security/security.c b/security/security.c
index d74f708c520ab..70a9fcfde8e32 100644
--- a/security/security.c
+++ b/security/security.c
@@ -49,7 +49,7 @@ static void __init do_security_initcalls(void)
}
/**
- * security_scaffolding_startup - initialzes the security scaffolding framework
+ * security_scaffolding_startup - initializes the security scaffolding framework
*
* This should be called early in the kernel initialization sequence.
*/
@@ -183,7 +183,7 @@ int mod_unreg_security (const char *name, struct security_operations *ops)
* capable - calls the currently loaded security module's capable() function with the specified capability
* @cap: the requested capability level.
*
- * This function calls the currently loaded security module's cabable()
+ * This function calls the currently loaded security module's capable()
* function with a pointer to the current task and the specified @cap value.
*
* This allows the security module to implement the capable function call
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 8819822d8e080..5a4a7988a7a75 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -24,6 +24,21 @@ config SECURITY_SELINUX_BOOTPARAM
If you are unsure how to answer this question, answer N.
+config SECURITY_SELINUX_BOOTPARAM_VALUE
+ int "NSA SELinux boot parameter default value"
+ depends on SECURITY_SELINUX_BOOTPARAM
+ range 0 1
+ default 1
+ help
+ This option sets the default value for the kernel parameter
+ 'selinux', which allows SELinux to be disabled at boot. If this
+ option is set to 0 (zero), the SELinux kernel parameter will
+ default to 0, disabling SELinux at bootup. If this option is
+ set to 1 (one), the SELinux kernel paramater will default to 1,
+ enabling SELinux at bootup.
+
+ If you are unsure how to answer this question, answer 1.
+
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 587d63bd68610..3dbd39c5a1db7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -43,6 +43,7 @@
#include <linux/kd.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
+#include <linux/tty.h>
#include <net/icmp.h>
#include <net/ip.h> /* for sysctl_local_port_range[] */
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
@@ -62,7 +63,6 @@
#include <linux/nfs_mount.h>
#include <net/ipv6.h>
#include <linux/hugetlb.h>
-#include <linux/major.h>
#include <linux/personality.h>
#include "avc.h"
@@ -87,7 +87,7 @@ __setup("enforcing=", enforcing_setup);
#endif
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
-int selinux_enabled = 1;
+int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
static int __init selinux_enabled_setup(char *str)
{
@@ -1266,6 +1266,12 @@ static inline u32 file_to_av(struct file *file)
int inode_security_set_sid(struct inode *inode, u32 sid)
{
struct inode_security_struct *isec = inode->i_security;
+ struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+
+ if (!sbsec->initialized) {
+ /* Defer initialization to selinux_complete_init. */
+ return 0;
+ }
down(&isec->sem);
isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -1726,72 +1732,40 @@ static void selinux_bprm_free_security(struct linux_binprm *bprm)
kfree(bsec);
}
-/* Create an open file that refers to the null device.
- Derived from the OpenWall LSM. */
-struct file *open_devnull(void)
-{
- struct inode *inode;
- struct dentry *dentry;
- struct file *file = NULL;
- struct inode_security_struct *isec;
- dev_t dev;
-
- inode = new_inode(current->fs->rootmnt->mnt_sb);
- if (!inode)
- goto out;
-
- dentry = dget(d_alloc_root(inode));
- if (!dentry)
- goto out_iput;
-
- file = get_empty_filp();
- if (!file)
- goto out_dput;
-
- dev = MKDEV(MEM_MAJOR, 3); /* null device */
-
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = 0;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_state = I_DIRTY; /* so that mark_inode_dirty won't touch us */
-
- isec = inode->i_security;
- isec->sid = SECINITSID_DEVNULL;
- isec->sclass = SECCLASS_CHR_FILE;
- isec->initialized = 1;
-
- file->f_flags = O_RDWR;
- file->f_mode = FMODE_READ | FMODE_WRITE;
- file->f_dentry = dentry;
- file->f_vfsmnt = mntget(current->fs->rootmnt);
- file->f_pos = 0;
-
- init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, dev);
- if (inode->i_fop->open(inode, file))
- goto out_fput;
-
-out:
- return file;
-out_fput:
- mntput(file->f_vfsmnt);
- put_filp(file);
-out_dput:
- dput(dentry);
-out_iput:
- iput(inode);
- file = NULL;
- goto out;
-}
+extern struct vfsmount *selinuxfs_mount;
+extern struct dentry *selinux_null;
/* Derived from fs/exec.c:flush_old_files. */
static inline void flush_unauthorized_files(struct files_struct * files)
{
struct avc_audit_data ad;
struct file *file, *devnull = NULL;
+ struct tty_struct *tty = current->signal->tty;
long j = -1;
+ if (tty) {
+ file_list_lock();
+ file = list_entry(tty->tty_files.next, typeof(*file), f_list);
+ if (file) {
+ /* Revalidate access to controlling tty.
+ Use inode_has_perm on the tty inode directly rather
+ than using file_has_perm, as this particular open
+ file may belong to another process and we are only
+ interested in the inode-based check here. */
+ struct inode *inode = file->f_dentry->d_inode;
+ if (inode_has_perm(current, inode,
+ FILE__READ | FILE__WRITE,
+ NULL, NULL)) {
+ /* Reset controlling tty. */
+ current->signal->tty = NULL;
+ current->signal->tty_old_pgrp = 0;
+ }
+ }
+ file_list_unlock();
+ }
+
+ /* Revalidate access to inherited open files. */
+
AVC_AUDIT_DATA_INIT(&ad,FS);
spin_lock(&files->file_lock);
@@ -1826,7 +1800,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
if (devnull) {
atomic_inc(&devnull->f_count);
} else {
- devnull = open_devnull();
+ devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
if (!devnull) {
put_unused_fd(fd);
fput(file);
@@ -2822,7 +2796,7 @@ static void selinux_task_to_inode(struct task_struct *p,
/* Returns error only if unable to parse addresses */
static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad)
{
- int offset, ihlen, ret;
+ int offset, ihlen, ret = -EINVAL;
struct iphdr _iph, *ih;
offset = skb->nh.raw - skb->data;
@@ -2836,6 +2810,7 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad
ad->u.net.v4info.saddr = ih->saddr;
ad->u.net.v4info.daddr = ih->daddr;
+ ret = 0;
switch (ih->protocol) {
case IPPROTO_TCP: {
@@ -2883,7 +2858,7 @@ out:
static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad)
{
u8 nexthdr;
- int ret, offset;
+ int ret = -EINVAL, offset;
struct ipv6hdr _ipv6h, *ip6;
offset = skb->nh.raw - skb->data;
@@ -2893,6 +2868,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad
ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+ ret = 0;
nexthdr = ip6->nexthdr;
offset += sizeof(_ipv6h);
@@ -3082,6 +3058,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
goto out;
AVC_AUDIT_DATA_INIT(&ad,NET);
ad.u.net.sport = htons(snum);
+ ad.u.net.family = family;
err = avc_has_perm(isec->sid, sid,
isec->sclass,
SOCKET__NAME_BIND, NULL, &ad);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 975a17708de83..57c2c8eaf060f 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/security.h>
+#include <linux/major.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -68,40 +69,15 @@ enum sel_inos {
SEL_DISABLE /* disable SELinux until next reboot */
};
+#define TMPBUFLEN 12
static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
- char *page;
+ char tmpbuf[TMPBUFLEN];
ssize_t length;
- ssize_t end;
-
- if (count < 0 || count > PAGE_SIZE)
- return -EINVAL;
- if (!(page = (char*)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
- length = scnprintf(page, PAGE_SIZE, "%d", selinux_enforcing);
- if (length < 0) {
- free_page((unsigned long)page);
- return length;
- }
-
- if (*ppos >= length) {
- free_page((unsigned long)page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- if (copy_to_user(buf, (char *) page + *ppos, count)) {
- count = -EFAULT;
- goto out;
- }
- *ppos = end;
-out:
- free_page((unsigned long)page);
- return count;
+ length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_enforcing);
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
@@ -119,10 +95,9 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf,
/* No partial writes. */
return -EINVAL;
}
- page = (char*)__get_free_page(GFP_KERNEL);
+ page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
@@ -170,10 +145,9 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf,
/* No partial writes. */
return -EINVAL;
}
- page = (char*)__get_free_page(GFP_KERNEL);
+ page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
@@ -204,37 +178,11 @@ static struct file_operations sel_disable_ops = {
static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
- char *page;
+ char tmpbuf[TMPBUFLEN];
ssize_t length;
- ssize_t end;
- if (count < 0 || count > PAGE_SIZE)
- return -EINVAL;
- if (!(page = (char*)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
-
- length = scnprintf(page, PAGE_SIZE, "%u", POLICYDB_VERSION_MAX);
- if (length < 0) {
- free_page((unsigned long)page);
- return length;
- }
-
- if (*ppos >= length) {
- free_page((unsigned long)page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- if (copy_to_user(buf, (char *) page + *ppos, count)) {
- count = -EFAULT;
- goto out;
- }
- *ppos = end;
-out:
- free_page((unsigned long)page);
- return count;
+ length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
static struct file_operations sel_policyvers_ops = {
@@ -247,37 +195,11 @@ static int sel_make_bools(void);
static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
- char *page;
+ char tmpbuf[TMPBUFLEN];
ssize_t length;
- ssize_t end;
-
- if (count < 0 || count > PAGE_SIZE)
- return -EINVAL;
- if (!(page = (char*)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
- length = scnprintf(page, PAGE_SIZE, "%d", selinux_mls_enabled);
- if (length < 0) {
- free_page((unsigned long)page);
- return length;
- }
-
- if (*ppos >= length) {
- free_page((unsigned long)page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- if (copy_to_user(buf, (char *) page + *ppos, count)) {
- count = -EFAULT;
- goto out;
- }
- *ppos = end;
-out:
- free_page((unsigned long)page);
- return count;
+ length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled);
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
static struct file_operations sel_mls_ops = {
@@ -352,10 +274,9 @@ static ssize_t sel_write_context(struct file * file, const char __user * buf,
/* No partial writes. */
return -EINVAL;
}
- page = (char*)__get_free_page(GFP_KERNEL);
+ page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
@@ -390,103 +311,31 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[SEL_USER] = sel_write_user,
};
-/* an argresp is stored in an allocated page and holds the
- * size of the argument or response, along with its content
- */
-struct argresp {
- ssize_t size;
- char data[0];
-};
-
-#define PAYLOAD_SIZE (PAGE_SIZE - sizeof(struct argresp))
-
-/*
- * transaction based IO methods.
- * The file expects a single write which triggers the transaction, and then
- * possibly a read which collects the result - which is stored in a
- * file-local buffer.
- */
-static ssize_t TA_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
+static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
ino_t ino = file->f_dentry->d_inode->i_ino;
- struct argresp *ar;
- ssize_t rv = 0;
+ char *data;
+ ssize_t rv;
if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino])
return -EINVAL;
- if (file->private_data)
- return -EINVAL; /* only one write allowed per open */
- if (size > PAYLOAD_SIZE - 1) /* allow one byte for null terminator */
- return -EFBIG;
- ar = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!ar)
- return -ENOMEM;
- memset(ar, 0, PAGE_SIZE); /* clear buffer, particularly last byte */
- ar->size = 0;
- down(&file->f_dentry->d_inode->i_sem);
- if (file->private_data)
- rv = -EINVAL;
- else
- file->private_data = ar;
- up(&file->f_dentry->d_inode->i_sem);
- if (rv) {
- kfree(ar);
- return rv;
- }
- if (copy_from_user(ar->data, buf, size))
- return -EFAULT;
+ data = simple_transaction_get(file, buf, size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
- rv = write_op[ino](file, ar->data, size);
+ rv = write_op[ino](file, data, size);
if (rv>0) {
- ar->size = rv;
+ simple_transaction_set(file, rv);
rv = size;
}
return rv;
}
-static ssize_t TA_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
-{
- struct argresp *ar;
- ssize_t rv = 0;
-
- if (file->private_data == NULL)
- rv = TA_write(file, buf, 0, pos);
- if (rv < 0)
- return rv;
-
- ar = file->private_data;
- if (!ar)
- return 0;
- if (*pos >= ar->size)
- return 0;
- if (*pos + size > ar->size)
- size = ar->size - *pos;
- if (copy_to_user(buf, ar->data + *pos, size))
- return -EFAULT;
- *pos += size;
- return size;
-}
-
-static int TA_open(struct inode *inode, struct file *file)
-{
- file->private_data = NULL;
- return 0;
-}
-
-static int TA_release(struct inode *inode, struct file *file)
-{
- void *p = file->private_data;
- file->private_data = NULL;
- kfree(p);
- return 0;
-}
-
static struct file_operations transaction_ops = {
- .write = TA_write,
- .read = TA_read,
- .open = TA_open,
- .release = TA_release,
+ .write = selinux_transaction_write,
+ .read = simple_transaction_read,
+ .release = simple_transaction_release,
};
/*
@@ -534,7 +383,8 @@ static ssize_t sel_write_access(struct file * file, char *buf, size_t size)
if (length < 0)
goto out2;
- length = scnprintf(buf, PAYLOAD_SIZE, "%x %x %x %x %u",
+ length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
+ "%x %x %x %x %u",
avd.allowed, avd.decided,
avd.auditallow, avd.auditdeny,
avd.seqno);
@@ -588,7 +438,7 @@ static ssize_t sel_write_create(struct file * file, char *buf, size_t size)
if (length < 0)
goto out2;
- if (len > PAYLOAD_SIZE) {
+ if (len > SIMPLE_TRANSACTION_LIMIT) {
printk(KERN_ERR "%s: context size (%u) exceeds payload "
"max\n", __FUNCTION__, len);
length = -ERANGE;
@@ -649,7 +499,7 @@ static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size)
if (length < 0)
goto out2;
- if (len > PAYLOAD_SIZE) {
+ if (len > SIMPLE_TRANSACTION_LIMIT) {
length = -ERANGE;
goto out3;
}
@@ -709,7 +559,7 @@ static ssize_t sel_write_user(struct file * file, char *buf, size_t size)
length = rc;
goto out3;
}
- if ((length + len) >= PAYLOAD_SIZE) {
+ if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
kfree(newcon);
length = -ERANGE;
goto out3;
@@ -766,11 +616,10 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
ret = -EINVAL;
goto out;
}
- if (!(page = (char*)__get_free_page(GFP_KERNEL))) {
+ if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) {
ret = -ENOMEM;
goto out;
}
- memset(page, 0, PAGE_SIZE);
inode = filep->f_dentry->d_inode;
cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
@@ -832,12 +681,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
/* No partial writes. */
goto out;
}
- page = (char*)__get_free_page(GFP_KERNEL);
+ page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page) {
length = -ENOMEM;
goto out;
}
- memset(page, 0, PAGE_SIZE);
if (copy_from_user(page, buf, count))
goto out;
@@ -891,14 +739,12 @@ static ssize_t sel_commit_bools_write(struct file *filep,
/* No partial writes. */
goto out;
}
- page = (char*)__get_free_page(GFP_KERNEL);
+ page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page) {
length = -ENOMEM;
goto out;
}
- memset(page, 0, PAGE_SIZE);
-
if (copy_from_user(page, buf, count))
goto out;
@@ -984,9 +830,8 @@ static int sel_make_bools(void)
sel_remove_bools(dir);
- if (!(page = (char*)__get_free_page(GFP_KERNEL)))
+ if (!(page = (char*)get_zeroed_page(GFP_KERNEL)))
return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
ret = security_get_bools(&num, &names, &values);
if (ret != 0)
@@ -1042,12 +887,17 @@ err:
goto out;
}
+#define NULL_FILE_NAME "null"
+
+struct dentry *selinux_null = NULL;
+
static int sel_fill_super(struct super_block * sb, void * data, int silent)
{
int ret;
struct dentry *dentry;
struct inode *inode;
struct qstr qname;
+ struct inode_security_struct *isec;
static struct tree_descr selinux_files[] = {
[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
@@ -1085,10 +935,29 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
if (ret)
goto out;
+ qname.name = NULL_FILE_NAME;
+ qname.len = strlen(qname.name);
+ qname.hash = full_name_hash(qname.name, qname.len);
+ dentry = d_alloc(sb->s_root, &qname);
+ if (!dentry)
+ return -ENOMEM;
+
+ inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
+ if (!inode)
+ goto out;
+ isec = (struct inode_security_struct*)inode->i_security;
+ isec->sid = SECINITSID_DEVNULL;
+ isec->sclass = SECCLASS_CHR_FILE;
+ isec->initialized = 1;
+
+ init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
+ d_add(dentry, inode);
+ selinux_null = dentry;
+
return 0;
out:
dput(dentry);
- printk(KERN_ERR "security: error creating conditional out_dput\n");
+ printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__);
return -ENOMEM;
}
@@ -1104,9 +973,24 @@ static struct file_system_type sel_fs_type = {
.kill_sb = kill_litter_super,
};
+struct vfsmount *selinuxfs_mount;
+
static int __init init_sel_fs(void)
{
- return selinux_enabled ? register_filesystem(&sel_fs_type) : 0;
+ int err;
+
+ if (!selinux_enabled)
+ return 0;
+ err = register_filesystem(&sel_fs_type);
+ if (!err) {
+ selinuxfs_mount = kern_mount(&sel_fs_type);
+ if (IS_ERR(selinuxfs_mount)) {
+ printk(KERN_ERR "selinuxfs: could not mount!\n");
+ err = PTR_ERR(selinuxfs_mount);
+ selinuxfs_mount = NULL;
+ }
+ }
+ return err;
}
__initcall(init_sel_fs);
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 8b4f596d05adb..66fbdbb58be83 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -28,12 +28,14 @@
(keyp->source_type << 9)) & \
AVTAB_HASH_MASK)
+static kmem_cache_t *avtab_node_cachep;
+
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
struct avtab_key *key, struct avtab_datum *datum)
{
struct avtab_node * newnode;
- newnode = (struct avtab_node *) kmalloc(sizeof(struct avtab_node),GFP_KERNEL);
+ newnode = kmem_cache_alloc(avtab_node_cachep, SLAB_KERNEL);
if (newnode == NULL)
return NULL;
memset(newnode, 0, sizeof(struct avtab_node));
@@ -226,7 +228,7 @@ void avtab_destroy(struct avtab *h)
while (cur != NULL) {
temp = cur;
cur = cur->next;
- kfree(temp);
+ kmem_cache_free(avtab_node_cachep, temp);
}
h->htable[i] = NULL;
}
@@ -399,3 +401,9 @@ bad:
goto out;
}
+void avtab_cache_init(void)
+{
+ avtab_node_cachep = kmem_cache_create("avtab_node",
+ sizeof(struct avtab_node),
+ 0, SLAB_PANIC, NULL, NULL);
+}
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 842636de107e4..f1d17575d9262 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -78,6 +78,8 @@ struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int
struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
+void avtab_cache_init(void);
+
#define AVTAB_HASH_BITS 15
#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 8e4423b1c7899..cad4257197193 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1034,6 +1034,7 @@ int security_load_policy(void *data, size_t len)
LOAD_LOCK;
if (!ss_initialized) {
+ avtab_cache_init();
if (policydb_read(&policydb, fp)) {
LOAD_UNLOCK;
return -EINVAL;
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
index 418f976c4554d..a681f7b969055 100644
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -2096,7 +2096,7 @@ static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, lof
unsigned copied=0;
CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
- printk("cs46xx: cs_read()+ %d\n",count) );
+ printk("cs46xx: cs_read()+ %zd\n",count) );
state = (struct cs_state *)card->states[0];
if(!state)
return -ENODEV;
@@ -2157,9 +2157,9 @@ static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, lof
}
CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
- "_read() copy_to cnt=%d count=%d ", cnt,count) );
+ "_read() copy_to cnt=%d count=%zd ", cnt,count) );
CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " .dmasize=%d .count=%d buffer=%p ret=%d\n",
+ " .dmasize=%d .count=%d buffer=%p ret=%zd\n",
dmabuf->dmasize,dmabuf->count,buffer,ret) );
if (cs_copy_to_user(state, buffer,
@@ -2184,7 +2184,7 @@ out2:
up(&state->sem);
set_current_state(TASK_RUNNING);
CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
- printk("cs46xx: cs_read()- %d\n",ret) );
+ printk("cs46xx: cs_read()- %zd\n",ret) );
return ret;
}
@@ -2202,7 +2202,7 @@ static ssize_t cs_write(struct file *file, const char __user *buffer, size_t cou
int cnt;
CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
- printk("cs46xx: cs_write called, count = %d\n", count) );
+ printk("cs46xx: cs_write called, count = %zd\n", count) );
state = (struct cs_state *)card->states[1];
if(!state)
return -ENODEV;
@@ -2309,7 +2309,7 @@ out:
set_current_state(TASK_RUNNING);
CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 2,
- printk("cs46xx: cs_write()- ret=0x%x\n", ret) );
+ printk("cs46xx: cs_write()- ret=%zd\n", ret) );
return ret;
}
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
index d253dfea014fc..2f83ac8a4cee4 100644
--- a/sound/oss/harmony.c
+++ b/sound/oss/harmony.c
@@ -8,7 +8,7 @@
On older 715 machines you'll find the technically identical chip
called 'Vivace'. Both Harmony and Vicace are supported by this driver.
- Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@linuxcare.com>
+ Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@onefishtwo.ca>
Copyright 2000-2003 (c) Helge Deller <deller@gmx.de>
Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr>
Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr>
@@ -1321,7 +1321,7 @@ static void __exit cleanup_harmony(void)
}
-MODULE_AUTHOR("Alex DeVries <alex@linuxcare.com>");
+MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>");
MODULE_DESCRIPTION("Harmony sound driver");
MODULE_LICENSE("GPL");
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index 6ccdd096f9183..047f2b41adde8 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -207,7 +207,7 @@ int msnd_wait_TXDE(multisound_dev_t *dev)
register int timeout = 1000;
while(timeout-- > 0)
- if (inb(io + HP_ISR) & HPISR_TXDE)
+ if (msnd_inb(io + HP_ISR) & HPISR_TXDE)
return 0;
return -EIO;
@@ -219,7 +219,7 @@ int msnd_wait_HC0(multisound_dev_t *dev)
register int timeout = 1000;
while(timeout-- > 0)
- if (!(inb(io + HP_CVR) & HPCVR_HC))
+ if (!(msnd_inb(io + HP_CVR) & HPCVR_HC))
return 0;
return -EIO;
@@ -231,7 +231,7 @@ int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
spin_lock_irqsave(&dev->lock, flags);
if (msnd_wait_HC0(dev) == 0) {
- outb(cmd, dev->io + HP_CVR);
+ msnd_outb(cmd, dev->io + HP_CVR);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
@@ -248,9 +248,9 @@ int msnd_send_word(multisound_dev_t *dev, unsigned char high,
register unsigned int io = dev->io;
if (msnd_wait_TXDE(dev) == 0) {
- outb(high, io + HP_TXH);
- outb(mid, io + HP_TXM);
- outb(low, io + HP_TXL);
+ msnd_outb(high, io + HP_TXH);
+ msnd_outb(mid, io + HP_TXM);
+ msnd_outb(low, io + HP_TXL);
return 0;
}
@@ -272,8 +272,8 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
return -EIO;
- inb(dev->io + HP_RXL);
- inb(dev->io + HP_CVR);
+ msnd_inb(dev->io + HP_RXL);
+ msnd_inb(dev->io + HP_CVR);
return 0;
}
@@ -289,11 +289,11 @@ int msnd_enable_irq(multisound_dev_t *dev)
spin_lock_irqsave(&dev->lock, flags);
if (msnd_wait_TXDE(dev) == 0) {
- outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
+ msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
if (dev->type == msndClassic)
- outb(dev->irqid, dev->io + HP_IRQM);
- outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
- outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
+ msnd_outb(dev->irqid, dev->io + HP_IRQM);
+ msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
+ msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
enable_irq(dev->irq);
msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -320,9 +320,9 @@ int msnd_disable_irq(multisound_dev_t *dev)
spin_lock_irqsave(&dev->lock, flags);
if (msnd_wait_TXDE(dev) == 0) {
- outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+ msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
if (dev->type == msndClassic)
- outb(HPIRQ_NONE, dev->io + HP_IRQM);
+ msnd_outb(HPIRQ_NONE, dev->io + HP_IRQM);
disable_irq(dev->irq);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h
index 73148d2eefe78..35894807ef7e4 100644
--- a/sound/oss/msnd.h
+++ b/sound/oss/msnd.h
@@ -154,10 +154,11 @@
#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2)
#ifdef SLOWIO
-# undef outb
-# undef inb
-# define outb outb_p
-# define inb inb_p
+#define msnd_outb outb_p
+#define msnd_inb inb_p
+#else
+#define msnd_outb outb
+#define msnd_inb inb
#endif
/* JobQueueStruct */
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index eb345b603d9bd..7ebc5d33b90dc 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -136,9 +136,9 @@ static void reset_record_queue(void)
/* Critical section: bank 1 access */
spin_lock_irqsave(&dev.lock, flags);
- outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS);
isa_memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
spin_unlock_irqrestore(&dev.lock, flags);
for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
@@ -830,12 +830,12 @@ static __inline__ int pack_DARQ_to_DARF(register int bank)
/* Read data from the head (unprotected bank 1 access okay
since this is only called inside an interrupt) */
- outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS);
msnd_fifo_write(
&dev.DARF,
(char *)(dev.base + bank * DAR_BUFF_SIZE),
size);
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
return 1;
}
@@ -1091,7 +1091,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *regs)
{
/* Send ack to DSP */
- inb(dev.io + HP_RXL);
+ msnd_inb(dev.io + HP_RXL);
/* Evaluate queued DSP messages */
while (isa_readw(dev.DSPQ + JQS_wTail) != isa_readw(dev.DSPQ + JQS_wHead)) {
@@ -1120,15 +1120,15 @@ static int reset_dsp(void)
{
int timeout = 100;
- outb(HPDSPRESET_ON, dev.io + HP_DSPR);
+ msnd_outb(HPDSPRESET_ON, dev.io + HP_DSPR);
mdelay(1);
#ifndef MSND_CLASSIC
- dev.info = inb(dev.io + HP_INFO);
+ dev.info = msnd_inb(dev.io + HP_INFO);
#endif
- outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
+ msnd_outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
mdelay(1);
while (timeout-- > 0) {
- if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
+ if (msnd_inb(dev.io + HP_CVR) == HP_CVR_DEF)
return 0;
mdelay(1);
}
@@ -1202,9 +1202,9 @@ static int init_sma(void)
unsigned long flags;
#ifdef MSND_CLASSIC
- outb(dev.memid, dev.io + HP_MEMM);
+ msnd_outb(dev.memid, dev.io + HP_MEMM);
#endif
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
if (initted) {
mastVolLeft = isa_readw(dev.SMA + SMA_wCurrMastVolLeft);
mastVolRight = isa_readw(dev.SMA + SMA_wCurrMastVolRight);
@@ -1214,9 +1214,9 @@ static int init_sma(void)
/* Critical section: bank 1 access */
spin_lock_irqsave(&dev.lock, flags);
- outb(HPBLKSEL_1, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_1, dev.io + HP_BLKS);
isa_memset_io(dev.base, 0, 0x8000);
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
spin_unlock_irqrestore(&dev.lock, flags);
dev.pwDSPQData = (dev.base + DSPQ_DATA_BUFF);
@@ -1289,7 +1289,7 @@ static int __init calibrate_adc(WORD srate)
static int upload_dsp_code(void)
{
- outb(HPBLKSEL_0, dev.io + HP_BLKS);
+ msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS);
#ifndef HAVE_DSPCODEH
INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE);
if (!INITCODE) {
@@ -1326,9 +1326,9 @@ static int upload_dsp_code(void)
#ifdef MSND_CLASSIC
static void reset_proteus(void)
{
- outb(HPPRORESET_ON, dev.io + HP_PROR);
+ msnd_outb(HPPRORESET_ON, dev.io + HP_PROR);
mdelay(TIME_PRO_RESET);
- outb(HPPRORESET_OFF, dev.io + HP_PROR);
+ msnd_outb(HPPRORESET_OFF, dev.io + HP_PROR);
mdelay(TIME_PRO_RESET_DONE);
}
#endif
@@ -1338,8 +1338,8 @@ static int initialize(void)
int err, timeout;
#ifdef MSND_CLASSIC
- outb(HPWAITSTATE_0, dev.io + HP_WAIT);
- outb(HPBITMODE_16, dev.io + HP_BITM);
+ msnd_outb(HPWAITSTATE_0, dev.io + HP_WAIT);
+ msnd_outb(HPBITMODE_16, dev.io + HP_BITM);
reset_proteus();
#endif
@@ -1455,9 +1455,9 @@ static void __exit unload_multisound(void)
static int __init msnd_write_cfg(int cfg, int reg, int value)
{
- outb(reg, cfg);
- outb(value, cfg + 1);
- if (value != inb(cfg + 1)) {
+ msnd_outb(reg, cfg);
+ msnd_outb(value, cfg + 1);
+ if (value != msnd_inb(cfg + 1)) {
printk(KERN_ERR LOGNAME ": msnd_write_cfg: I/O error\n");
return -EIO;
}
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index 44ab698675d8e..438e64ecbd883 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -1346,18 +1346,20 @@ static int __init probe_waveartist(struct address_info *hw_config)
return 0;
}
- if (check_region(hw_config->io_base, 15)) {
+ if (!request_region(hw_config->io_base, 15, hw_config->name)) {
printk(KERN_WARNING "WaveArtist: I/O port conflict\n");
return 0;
}
if (hw_config->irq > 15 || hw_config->irq < 0) {
+ release_region(hw_config->io_base, 15);
printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n",
hw_config->irq);
return 0;
}
if (hw_config->dma != 3) {
+ release_region(hw_config->io_base, 15);
printk(KERN_WARNING "WaveArtist: Bad DMA %d\n",
hw_config->dma);
return 0;
@@ -1392,8 +1394,6 @@ attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *m
if (hw->dma != hw->dma2 && hw->dma2 != NO_DMA)
devc->audio_flags |= DMA_DUPLEX;
- request_region(hw->io_base, 15, devc->hw.name);
-
devc->mix = mix;
devc->dev_no = waveartist_init(devc);